Source for file phpagi.php

Documentation is available at phpagi.php

  1. <?php
  2.  
  3. /**
  4. * phpagi.php : PHP AGI Functions for Asterisk
  5. * Website: http://phpagi.sourceforge.net/
  6. *
  7. * $Id: phpagi.php,v 2.20 2010/09/30 02:21:00 masham Exp $
  8. *
  9. * Copyright (c) 2003 - 2010 Matthew Asham <matthew@ochrelabs.com>, David Eder <david@eder.us> and others
  10. * All Rights Reserved.
  11. *
  12. * This software is released under the terms of the GNU Lesser General Public License v2.1
  13. * A copy of which is available from http://www.gnu.org/copyleft/lesser.html
  14. *
  15. * We would be happy to list your phpagi based application on the phpagi
  16. * website.  Drop me an Email if you'd like us to list your program.
  17. *
  18. * Written for PHP 4.3.4, should work with older PHP 4.x versions.
  19. *
  20. * Please submit bug reports, patches, etc to http://sourceforge.net/projects/phpagi/
  21. * Gracias. :)
  22. *
  23. *
  24. @package phpAGI
  25. @version 2.0
  26. */
  27.  
  28. if (!class_exists('AGI_AsteriskManager'))
  29. {
  30.     require_once(dirname(__FILE__DIRECTORY_SEPARATOR 'phpagi-asmanager.php');
  31. }
  32.  
  33. define('AST_CONFIG_DIR''/etc/asterisk/');
  34. define('AST_SPOOL_DIR''/var/spool/asterisk/');
  35. define('AST_TMP_DIR'AST_SPOOL_DIR '/tmp/');
  36. define('DEFAULT_PHPAGI_CONFIG'AST_CONFIG_DIR '/phpagi.conf');
  37.  
  38. define('AST_DIGIT_ANY''0123456789#*');
  39.  
  40. define('AGIRES_OK'200);
  41.  
  42. define('AST_STATE_DOWN'0);
  43. define('AST_STATE_RESERVED'1);
  44. define('AST_STATE_OFFHOOK'2);
  45. define('AST_STATE_DIALING'3);
  46. define('AST_STATE_RING'4);
  47. define('AST_STATE_RINGING'5);
  48. define('AST_STATE_UP'6);
  49. define('AST_STATE_BUSY'7);
  50. define('AST_STATE_DIALING_OFFHOOK'8);
  51. define('AST_STATE_PRERING'9);
  52.  
  53. define('AUDIO_FILENO'3)// STDERR_FILENO + 1
  54.  
  55. /**
  56. * AGI class
  57. *
  58. @package phpAGI
  59. @link http://www.voip-info.org/wiki-Asterisk+agi
  60. @example examples/dtmf.php Get DTMF tones from the user and say the digits
  61. @example examples/input.php Get text input from the user and say it back
  62. @example examples/ping.php Ping an IP address
  63. */
  64. class AGI
  65. {
  66.     /**
  67.     * Request variables read in on initialization.
  68.     *
  69.     * Often contains any/all of the following:
  70.     *   agi_request - name of agi script
  71.     *   agi_channel - current channel
  72.     *   agi_language - current language
  73.     *   agi_type - channel type (SIP, ZAP, IAX, ...)
  74.     *   agi_uniqueid - unique id based on unix time
  75.     *   agi_callerid - callerID string
  76.     *   agi_dnid - dialed number id
  77.     *   agi_rdnis - referring DNIS number
  78.     *   agi_context - current context
  79.     *   agi_extension - extension dialed
  80.     *   agi_priority - current priority
  81.     *   agi_enhanced - value is 1.0 if started as an EAGI script
  82.     *   agi_accountcode - set by SetAccount in the dialplan
  83.     *   agi_network - value is yes if this is a fastagi
  84.     *   agi_network_script - name of the script to execute
  85.     *
  86.     * NOTE: program arguments are still in $_SERVER['argv'].
  87.     *
  88.     * @var array 
  89.     * @access public
  90.     */
  91.     var $request;
  92.  
  93.     /**
  94.     * Config variables
  95.     *
  96.     * @var array 
  97.     * @access public
  98.     */
  99.     var $config;
  100.  
  101.     /**
  102.     * Asterisk Manager
  103.     *
  104.     * @var AGI_AsteriskManager 
  105.     * @access public
  106.     */
  107.     var $asmanager;
  108.  
  109.     /**
  110.     * Input Stream
  111.     *
  112.     * @access private
  113.     */
  114.     var $in = NULL;
  115.  
  116.     /**
  117.     * Output Stream
  118.     *
  119.     * @access private
  120.     */
  121.     var $out = NULL;
  122.  
  123.     /**
  124.     * Audio Stream
  125.     *
  126.     * @access public
  127.     */
  128.     var $audio = NULL;
  129.  
  130.  
  131.     /**
  132.     * Application option delimiter
  133.     * 
  134.     * @access public
  135.     */
  136.     public $option_delim = ",";
  137.     
  138.     /**
  139.     * Constructor
  140.     *
  141.     * @param string $config is the name of the config file to parse
  142.     * @param array $optconfig is an array of configuration vars and vals, stuffed into $this->config['phpagi']
  143.     */
  144.     function __construct($config=NULL$optconfig=array())
  145.     {
  146.         // load config
  147.         if(!is_null($config&& file_exists($config))
  148.           $this->config = parse_ini_file($configtrue);
  149.         elseif(file_exists(DEFAULT_PHPAGI_CONFIG))
  150.           $this->config = parse_ini_file(DEFAULT_PHPAGI_CONFIGtrue);
  151.  
  152.         // If optconfig is specified, stuff vals and vars into 'phpagi' config array.
  153.         foreach($optconfig as $var=>$val)
  154.           $this->config['phpagi'][$var$val;
  155.  
  156.         // add default values to config for uninitialized values
  157.         if(!isset($this->config['phpagi']['error_handler'])) $this->config['phpagi']['error_handler'true;
  158.         if(!isset($this->config['phpagi']['debug'])) $this->config['phpagi']['debug'false;
  159.         if(!isset($this->config['phpagi']['admin'])) $this->config['phpagi']['admin'NULL;
  160.         if(!isset($this->config['phpagi']['tempdir'])) $this->config['phpagi']['tempdir'AST_TMP_DIR;
  161.  
  162.         // festival TTS config
  163.         if(!isset($this->config['festival']['text2wave'])) $this->config['festival']['text2wave'$this->which('text2wave');
  164.  
  165.         // swift TTS config
  166.         if(!isset($this->config['cepstral']['swift'])) $this->config['cepstral']['swift'$this->which('swift');
  167.  
  168.         ob_implicit_flush(true);
  169.  
  170.         // open stdin & stdout
  171.         $this->in = defined('STDIN'STDIN fopen('php://stdin''r');
  172.         $this->out = defined('STDOUT'STDOUT fopen('php://stdout''w');
  173.  
  174.         // initialize error handler
  175.         if($this->config['phpagi']['error_handler'== true)
  176.         {
  177.           set_error_handler('phpagi_error_handler');
  178.           global $phpagi_error_handler_email;
  179.           $phpagi_error_handler_email $this->config['phpagi']['admin'];
  180.           error_reporting(E_ALL);
  181.         }
  182.  
  183.         // make sure temp folder exists
  184.         $this->make_folder($this->config['phpagi']['tempdir']);
  185.  
  186.         // read the request
  187.         $str fgets($this->in);
  188.         while($str != "\n")
  189.         {
  190.           $this->request[substr($str0strpos($str':'))trim(substr($strstrpos($str':'1));
  191.           $str fgets($this->in);
  192.         }
  193.  
  194.         // open audio if eagi detected
  195.         if($this->request['agi_enhanced'== '1.0')
  196.         {
  197.           if(file_exists('/proc/' getmypid('/fd/3'))
  198.             $this->audio = fopen('/proc/' getmypid('/fd/3''r');
  199.           elseif(file_exists('/dev/fd/3'))
  200.           {
  201.             // may need to mount fdescfs
  202.             $this->audio = fopen('/dev/fd/3''r');
  203.           }
  204.           else
  205.             $this->conlog('Unable to open audio stream');
  206.  
  207.           if($this->audiostream_set_blocking($this->audio0);
  208.         }
  209.  
  210.         $this->conlog('AGI Request:');
  211.         $this->conlog(print_r($this->requesttrue));
  212.         $this->conlog('PHPAGI internal configuration:');
  213.         $this->conlog(print_r($this->configtrue));
  214.     }
  215.  
  216.     // *********************************************************************************************************
  217.     // **                             COMMANDS                                                                                            **
  218.     // *********************************************************************************************************
  219.  
  220.     /**
  221.     * Answer channel if not already in answer state.
  222.     *
  223.     * @link http://www.voip-info.org/wiki-answer
  224.     * @example examples/dtmf.php Get DTMF tones from the user and say the digits
  225.     * @example examples/input.php Get text input from the user and say it back
  226.     * @example examples/ping.php Ping an IP address
  227.     *
  228.     * @return array, see evaluate for return information.  ['result'] is 0 on success, -1 on failure.
  229.     */
  230.     function answer()
  231.     {
  232.         return $this->evaluate('ANSWER');
  233.     }
  234.  
  235.     /**
  236.     * Get the status of the specified channel. If no channel name is specified, return the status of the current channel.
  237.     *
  238.     * @link http://www.voip-info.org/wiki-channel+status
  239.     * @param string $channel 
  240.     * @return array, see evaluate for return information. ['data'] contains description.
  241.     */
  242.     function channel_status($channel='')
  243.     {
  244.         $ret $this->evaluate("CHANNEL STATUS $channel");
  245.         switch($ret['result'])
  246.         {
  247.           case -1$ret['data'trim("There is no channel that matches $channel")break;
  248.           case AST_STATE_DOWN$ret['data''Channel is down and available'break;
  249.           case AST_STATE_RESERVED$ret['data''Channel is down, but reserved'break;
  250.           case AST_STATE_OFFHOOK$ret['data''Channel is off hook'break;
  251.           case AST_STATE_DIALING$ret['data''Digits (or equivalent) have been dialed'break;
  252.           case AST_STATE_RING$ret['data''Line is ringing'break;
  253.           case AST_STATE_RINGING$ret['data''Remote end is ringing'break;
  254.           case AST_STATE_UP$ret['data''Line is up'break;
  255.           case AST_STATE_BUSY$ret['data''Line is busy'break;
  256.           case AST_STATE_DIALING_OFFHOOK$ret['data''Digits (or equivalent) have been dialed while offhook'break;
  257.           case AST_STATE_PRERING$ret['data''Channel has detected an incoming call and is waiting for ring'break;
  258.           default$ret['data'"Unknown ({$ret['result']})"break;
  259.         }
  260.         return $ret;
  261.     }
  262.  
  263.     /**
  264.     * Deletes an entry in the Asterisk database for a given family and key.
  265.     *
  266.     * @link http://www.voip-info.org/wiki-database+del
  267.     * @param string $family 
  268.     * @param string $key 
  269.     * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise.
  270.     */
  271.     function database_del($family$key)
  272.     {
  273.         return $this->evaluate("DATABASE DEL \"$family\" \"$key\"");
  274.     }
  275.  
  276.     /**
  277.     * Deletes a family or specific keytree within a family in the Asterisk database.
  278.     *
  279.     * @link http://www.voip-info.org/wiki-database+deltree
  280.     * @param string $family 
  281.     * @param string $keytree 
  282.     * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise.
  283.     */
  284.     function database_deltree($family$keytree='')
  285.     {
  286.         $cmd "DATABASE DELTREE \"$family\"";
  287.         if($keytree != ''$cmd .= " \"$keytree\"";
  288.         return $this->evaluate($cmd);
  289.     }
  290.  
  291.     /**
  292.     * Retrieves an entry in the Asterisk database for a given family and key.
  293.     *
  294.     * @link http://www.voip-info.org/wiki-database+get
  295.     * @param string $family 
  296.     * @param string $key 
  297.     * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 failure. ['data'] holds the value
  298.     */
  299.     function database_get($family$key)
  300.     {
  301.         return $this->evaluate("DATABASE GET \"$family\" \"$key\"");
  302.     }
  303.  
  304.     /**
  305.     * Adds or updates an entry in the Asterisk database for a given family, key, and value.
  306.     *
  307.     * @param string $family 
  308.     * @param string $key 
  309.     * @param string $value 
  310.     * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise
  311.     */
  312.     function database_put($family$key$value)
  313.     {
  314.         $value str_replace("\n"'\n'addslashes($value));
  315.         return $this->evaluate("DATABASE PUT \"$family\" \"$key\" \"$value\"");
  316.     }
  317.  
  318.  
  319.     /**
  320.     * Sets a global variable, using Asterisk 1.6 syntax.
  321.     *
  322.     * @link http://www.voip-info.org/wiki/view/Asterisk+cmd+Set
  323.     *
  324.     * @param string $pVariable 
  325.     * @param string|int|float$pValue 
  326.     * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise
  327.     */
  328.     function set_global_var($pVariable$pValue)
  329.     {
  330.         if (is_numeric($pValue))
  331.             return $this->evaluate("Set({$pVariable}={$pValue},g);");
  332.         else
  333.             return $this->evaluate("Set({$pVariable}=\"{$pValue}\",g);");
  334.     }
  335.  
  336.  
  337.     /**
  338.     * Sets a variable, using Asterisk 1.6 syntax.
  339.     *
  340.     * @link http://www.voip-info.org/wiki/view/Asterisk+cmd+Set
  341.     *
  342.     * @param string $pVariable 
  343.     * @param string|int|float$pValue 
  344.     * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise
  345.     */
  346.     function set_var($pVariable$pValue)
  347.     {
  348.         if (is_numeric($pValue))
  349.             return $this->evaluate("Set({$pVariable}={$pValue});");
  350.         else
  351.             return $this->evaluate("Set({$pVariable}=\"{$pValue}\");");
  352.     }
  353.  
  354.  
  355.     /**
  356.     * Executes the specified Asterisk application with given options.
  357.     *
  358.     * @link http://www.voip-info.org/wiki-exec
  359.     * @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands
  360.     * @param string $application 
  361.     * @param mixed $options 
  362.     * @return array, see evaluate for return information. ['result'] is whatever the application returns, or -2 on failure to find application
  363.     */
  364.     function exec($application$options)
  365.     {
  366.         if(is_array($options)) $options join('|'$options);
  367.         return $this->evaluate("EXEC $application $options");
  368.     }
  369.  
  370.     /**
  371.     * Plays the given file and receives DTMF data.
  372.     *
  373.     * This is similar to STREAM FILE, but this command can accept and return many DTMF digits,
  374.     * while STREAM FILE returns immediately after the first DTMF digit is detected.
  375.     *
  376.     * Asterisk looks for the file to play in /var/lib/asterisk/sounds by default.
  377.     *
  378.     * If the user doesn't press any keys when the message plays, there is $timeout milliseconds
  379.     * of silence then the command ends.
  380.     *
  381.     * The user has the opportunity to press a key at any time during the message or the
  382.     * post-message silence. If the user presses a key while the message is playing, the
  383.     * message stops playing. When the first key is pressed a timer starts counting for
  384.     * $timeout milliseconds. Every time the user presses another key the timer is restarted.
  385.     * The command ends when the counter goes to zero or the maximum number of digits is entered,
  386.     * whichever happens first.
  387.     *
  388.     * If you don't specify a time out then a default timeout of 2000 is used following a pressed
  389.     * digit. If no digits are pressed then 6 seconds of silence follow the message.
  390.     *
  391.     * If you don't specify $max_digits then the user can enter as many digits as they want.
  392.     *
  393.     * Pressing the # key has the same effect as the timer running out: the command ends and
  394.     * any previously keyed digits are returned. A side effect of this is that there is no
  395.     * way to read a # key using this command.
  396.     *
  397.     * @example examples/ping.php Ping an IP address
  398.     *
  399.     * @link http://www.voip-info.org/wiki-get+data
  400.     * @param string $filename file to play. Do not include file extension.
  401.     * @param integer $timeout milliseconds
  402.     * @param integer $max_digits 
  403.     * @return array, see evaluate for return information. ['result'] holds the digits and ['data'] holds the timeout if present.
  404.     *
  405.     *  This differs from other commands with return DTMF as numbers representing ASCII characters.
  406.     */
  407.     function get_data($filename$timeout=NULL$max_digits=NULL)
  408.     {
  409.         return $this->evaluate(rtrim("GET DATA $filename $timeout $max_digits"));
  410.     }
  411.  
  412.     /**
  413.     * Fetch the value of a variable.
  414.     *
  415.     * Does not work with global variables. Does not work with some variables that are generated by modules.
  416.     *
  417.     * @link http://www.voip-info.org/wiki-get+variable
  418.     * @link http://www.voip-info.org/wiki-Asterisk+variables
  419.     * @param string $variable name
  420.     * @param boolean $getvalue return the value only
  421.     * @return array, see evaluate for return information. ['result'] is 0 if variable hasn't been set, 1 if it has. ['data'] holds the value. returns value if $getvalue is TRUE
  422.     */
  423.     function get_variable($variable,$getvalue=FALSE)
  424.     {
  425.         $res=$this->evaluate("GET VARIABLE $variable");
  426.  
  427.         if($getvalue==FALSE)
  428.           return($res);
  429.  
  430.         return($res['data']);
  431.     }
  432.  
  433.  
  434.     /**
  435.     * Fetch the value of a full variable.
  436.     *
  437.     *
  438.     * @link http://www.voip-info.org/wiki/view/get+full+variable
  439.     * @link http://www.voip-info.org/wiki-Asterisk+variables
  440.     * @param string $variable name
  441.     * @param string $channel channel
  442.     * @param boolean $getvalue return the value only
  443.     * @return array, see evaluate for return information. ['result'] is 0 if variable hasn't been set, 1 if it has. ['data'] holds the value.  returns value if $getvalue is TRUE
  444.     */
  445.     function get_fullvariable($variable,$channel=FALSE,$getvalue=FALSE)
  446.     {
  447.       if($channel==FALSE){
  448.         $req $variable;
  449.       else {
  450.         $req $variable.' '.$channel;
  451.       }
  452.       
  453.       $res=$this->evaluate('GET VARIABLE FULL '.$req);
  454.       
  455.       if($getvalue==FALSE)
  456.         return($res);
  457.       
  458.       return($res['data']);
  459.       
  460.     }
  461.  
  462.     /**
  463.     * Hangup the specified channel. If no channel name is given, hang up the current channel.
  464.     *
  465.     * With power comes responsibility. Hanging up channels other than your own isn't something
  466.     * that is done routinely. If you are not sure why you are doing so, then don't.
  467.     *
  468.     * @link http://www.voip-info.org/wiki-hangup
  469.     * @example examples/dtmf.php Get DTMF tones from the user and say the digits
  470.     * @example examples/input.php Get text input from the user and say it back
  471.     * @example examples/ping.php Ping an IP address
  472.     *
  473.     * @param string $channel 
  474.     * @return array, see evaluate for return information. ['result'] is 1 on success, -1 on failure.
  475.     */
  476.     function hangup($channel='')
  477.     {
  478.         return $this->evaluate("HANGUP $channel");
  479.     }
  480.  
  481.     /**
  482.     * Does nothing.
  483.     *
  484.     * @link http://www.voip-info.org/wiki-noop
  485.     * @return array, see evaluate for return information.
  486.     */
  487.     function noop($string="")
  488.     {
  489.         return $this->evaluate("NOOP \"$string\"");
  490.     }
  491.  
  492.     /**
  493.     * Receive a character of text from a connected channel. Waits up to $timeout milliseconds for
  494.     * a character to arrive, or infinitely if $timeout is zero.
  495.     *
  496.     * @link http://www.voip-info.org/wiki-receive+char
  497.     * @param integer $timeout milliseconds
  498.     * @return array, see evaluate for return information. ['result'] is 0 on timeout or not supported, -1 on failure. Otherwise
  499.     *  it is the decimal value of the DTMF tone. Use chr() to convert to ASCII.
  500.     */
  501.     function receive_char($timeout=-1)
  502.     {
  503.         return $this->evaluate("RECEIVE CHAR $timeout");
  504.     }
  505.  
  506.     /**
  507.     * Record sound to a file until an acceptable DTMF digit is received or a specified amount of
  508.     * time has passed. Optionally the file BEEP is played before recording begins.
  509.     *
  510.     * @link http://www.voip-info.org/wiki-record+file
  511.     * @param string $file to record, without extension, often created in /var/lib/asterisk/sounds
  512.     * @param string $format of the file. GSM and WAV are commonly used formats. MP3 is read-only and thus cannot be used.
  513.     * @param string $escape_digits 
  514.     * @param integer $timeout is the maximum record time in milliseconds, or -1 for no timeout.
  515.     * @param integer $offset to seek to without exceeding the end of the file.
  516.     * @param boolean $beep 
  517.     * @param integer $silence number of seconds of silence allowed before the function returns despite the
  518.     *  lack of dtmf digits or reaching timeout.
  519.     * @return array, see evaluate for return information. ['result'] is -1 on error, 0 on hangup, otherwise a decimal value of the
  520.     *  DTMF tone. Use chr() to convert to ASCII.
  521.     */
  522.     function record_file($file$format$escape_digits=''$timeout=-1$offset=NULL$beep=false$silence=NULL)
  523.     {
  524.         $cmd trim("RECORD FILE $file $format \"$escape_digits\" $timeout $offset");
  525.         if($beep$cmd .= ' BEEP';
  526.         if(!is_null($silence)) $cmd .= " s=$silence";
  527.         return $this->evaluate($cmd);
  528.     }
  529.  
  530.     /**
  531.     * Say the given digit string, returning early if any of the given DTMF escape digits are received on the channel.
  532.     *
  533.     * @link http://www.voip-info.org/wiki-say+digits
  534.     * @param integer $digits 
  535.     * @param string $escape_digits 
  536.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  537.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  538.     */
  539.     function say_digits($digits$escape_digits='')
  540.     {
  541.         return $this->evaluate("SAY DIGITS $digits \"$escape_digits\"");
  542.     }
  543.  
  544.     /**
  545.     * Say the given number, returning early if any of the given DTMF escape digits are received on the channel.
  546.     *
  547.     * @link http://www.voip-info.org/wiki-say+number
  548.     * @param integer $number 
  549.     * @param string $escape_digits 
  550.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  551.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  552.     */
  553.     function say_number($number$escape_digits='')
  554.     {
  555.         return $this->evaluate("SAY NUMBER $number \"$escape_digits\"");
  556.     }
  557.  
  558.     /**
  559.     * Say the given character string, returning early if any of the given DTMF escape digits are received on the channel.
  560.     *
  561.     * @link http://www.voip-info.org/wiki-say+phonetic
  562.     * @param string $text 
  563.     * @param string $escape_digits 
  564.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  565.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  566.     */
  567.     function say_phonetic($text$escape_digits='')
  568.     {
  569.         return $this->evaluate("SAY PHONETIC $text \"$escape_digits\"");
  570.     }
  571.  
  572.     /**
  573.     * Say a given time, returning early if any of the given DTMF escape digits are received on the channel.
  574.     *
  575.     * @link http://www.voip-info.org/wiki-say+time
  576.     * @param integer $time number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).
  577.     * @param string $escape_digits 
  578.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  579.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  580.     */
  581.     function say_time($time=NULL$escape_digits='')
  582.     {
  583.         if(is_null($time)) $time time();
  584.         return $this->evaluate("SAY TIME $time \"$escape_digits\"");
  585.     }
  586.  
  587.     /**
  588.     * Send the specified image on a channel.
  589.     *
  590.     * Most channels do not support the transmission of images.
  591.     *
  592.     * @link http://www.voip-info.org/wiki-send+image
  593.     * @param string $image without extension, often in /var/lib/asterisk/images
  594.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if the image is sent or
  595.     *  channel does not support image transmission.
  596.     */
  597.     function send_image($image)
  598.     {
  599.         return $this->evaluate("SEND IMAGE $image");
  600.     }
  601.  
  602.     /**
  603.     * Send the given text to the connected channel.
  604.     *
  605.     * Most channels do not support transmission of text.
  606.     *
  607.     * @link http://www.voip-info.org/wiki-send+text
  608.     * @param $text 
  609.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if the text is sent or
  610.     *  channel does not support text transmission.
  611.     */
  612.     function send_text($text)
  613.     {
  614.         return $this->evaluate("SEND TEXT \"$text\"");
  615.     }
  616.  
  617.     /**
  618.     * Cause the channel to automatically hangup at $time seconds in the future.
  619.     * If $time is 0 then the autohangup feature is disabled on this channel.
  620.     *
  621.     * If the channel is hungup prior to $time seconds, this setting has no effect.
  622.     *
  623.     * @link http://www.voip-info.org/wiki-set+autohangup
  624.     * @param integer $time until automatic hangup
  625.     * @return array, see evaluate for return information.
  626.     */
  627.     function set_autohangup($time=0)
  628.     {
  629.         return $this->evaluate("SET AUTOHANGUP $time");
  630.     }
  631.  
  632.     /**
  633.     * Changes the caller ID of the current channel.
  634.     *
  635.     * @link http://www.voip-info.org/wiki-set+callerid
  636.     * @param string $cid example: "John Smith"<1234567>
  637.     *  This command will let you take liberties with the <caller ID specification> but the format shown in the example above works
  638.     *  well: the name enclosed in double quotes followed immediately by the number inside angle brackets. If there is no name then
  639.     *  you can omit it. If the name contains no spaces you can omit the double quotes around it. The number must follow the name
  640.     *  immediately; don't put a space between them. The angle brackets around the number are necessary; if you omit them the
  641.     *  number will be considered to be part of the name.
  642.     * @return array, see evaluate for return information.
  643.     */
  644.     function set_callerid($cid)
  645.     {
  646.         return $this->evaluate("SET CALLERID $cid");
  647.     }
  648.  
  649.     /**
  650.     * Sets the context for continuation upon exiting the application.
  651.     *
  652.     * Setting the context does NOT automatically reset the extension and the priority; if you want to start at the top of the new
  653.     * context you should set extension and priority yourself.
  654.     *
  655.     * If you specify a non-existent context you receive no error indication (['result'] is still 0) but you do get a
  656.     * warning message on the Asterisk console.
  657.     *
  658.     * @link http://www.voip-info.org/wiki-set+context
  659.     * @param string $context 
  660.     * @return array, see evaluate for return information.
  661.     */
  662.     function set_context($context)
  663.     {
  664.         return $this->evaluate("SET CONTEXT $context");
  665.     }
  666.  
  667.     /**
  668.     * Set the extension to be used for continuation upon exiting the application.
  669.     *
  670.     * Setting the extension does NOT automatically reset the priority. If you want to start with the first priority of the
  671.     * extension you should set the priority yourself.
  672.     *
  673.     * If you specify a non-existent extension you receive no error indication (['result'] is still 0) but you do
  674.     * get a warning message on the Asterisk console.
  675.     *
  676.     * @link http://www.voip-info.org/wiki-set+extension
  677.     * @param string $extension 
  678.     * @return array, see evaluate for return information.
  679.     */
  680.     function set_extension($extension)
  681.     {
  682.         return $this->evaluate("SET EXTENSION $extension");
  683.     }
  684.  
  685.     /**
  686.     * Enable/Disable Music on hold generator.
  687.     *
  688.     * @link http://www.voip-info.org/wiki-set+music
  689.     * @param boolean $enabled 
  690.     * @param string $class 
  691.     * @return array, see evaluate for return information.
  692.     */
  693.     function set_music($enabled=true$class='')
  694.     {
  695.         $enabled ($enabled'ON' 'OFF';
  696.         return $this->evaluate("SET MUSIC $enabled $class");
  697.     }
  698.  
  699.     /**
  700.     * Set the priority to be used for continuation upon exiting the application.
  701.     *
  702.     * If you specify a non-existent priority you receive no error indication (['result'] is still 0)
  703.     * and no warning is issued on the Asterisk console.
  704.     *
  705.     * @link http://www.voip-info.org/wiki-set+priority
  706.     * @param integer $priority 
  707.     * @return array, see evaluate for return information.
  708.     */
  709.     function set_priority($priority)
  710.     {
  711.         return $this->evaluate("SET PRIORITY $priority");
  712.     }
  713.  
  714.     /**
  715.     * Sets a variable to the specified value. The variables so created can later be used by later using ${<variablename>}
  716.     * in the dialplan.
  717.     *
  718.     * These variables live in the channel Asterisk creates when you pickup a phone and as such they are both local and temporary.
  719.     * Variables created in one channel can not be accessed by another channel. When you hang up the phone, the channel is deleted
  720.     * and any variables in that channel are deleted as well.
  721.     *
  722.     * @link http://www.voip-info.org/wiki-set+variable
  723.     * @param string $variable is case sensitive
  724.     * @param string $value 
  725.     * @return array, see evaluate for return information.
  726.     */
  727.     function set_variable($variable$value)
  728.     {
  729.         $value str_replace("\n"'\n'addslashes($value));
  730.         return $this->evaluate("SET VARIABLE $variable \"$value\"");
  731.     }
  732.  
  733.     /**
  734.     * Play the given audio file, allowing playback to be interrupted by a DTMF digit. This command is similar to the GET DATA
  735.     * command but this command returns after the first DTMF digit has been pressed while GET DATA can accumulated any number of
  736.     * digits before returning.
  737.     *
  738.     * @example examples/ping.php Ping an IP address
  739.     *
  740.     * @link http://www.voip-info.org/wiki-stream+file
  741.     * @param string $filename without extension, often in /var/lib/asterisk/sounds
  742.     * @param string $escape_digits 
  743.     * @param integer $offset 
  744.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  745.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  746.     */
  747.     function stream_file($filename$escape_digits=''$offset=0)
  748.     {
  749.         return $this->evaluate("STREAM FILE $filename \"$escape_digits\" $offset");
  750.     }
  751.  
  752.     /**
  753.     * Enable or disable TDD transmission/reception on the current channel.
  754.     *
  755.     * @link http://www.voip-info.org/wiki-tdd+mode
  756.     * @param string $setting can be on, off or mate
  757.     * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 if the channel is not TDD capable.
  758.     */
  759.     function tdd_mode($setting)
  760.     {
  761.         return $this->evaluate("TDD MODE $setting");
  762.     }
  763.  
  764.     /**
  765.     * Sends $message to the Asterisk console via the 'verbose' message system.
  766.     *
  767.     * If the Asterisk verbosity level is $level or greater, send $message to the console.
  768.     *
  769.     * The Asterisk verbosity system works as follows. The Asterisk user gets to set the desired verbosity at startup time or later
  770.     * using the console 'set verbose' command. Messages are displayed on the console if their verbose level is less than or equal
  771.     * to desired verbosity set by the user. More important messages should have a low verbose level; less important messages
  772.     * should have a high verbose level.
  773.     *
  774.     * @link http://www.voip-info.org/wiki-verbose
  775.     * @param string $message 
  776.     * @param integer $level from 1 to 4
  777.     * @return array, see evaluate for return information.
  778.     */
  779.     function verbose($message$level=1)
  780.     {
  781.         foreach(explode("\n"str_replace("\r\n""\n"print_r($messagetrue))) as $msg)
  782.         {
  783.           @syslog(LOG_WARNING$msg);
  784.           $ret $this->evaluate("VERBOSE \"$msg\" $level");
  785.         }
  786.         return $ret;
  787.     }
  788.  
  789.     /**
  790.     * Waits up to $timeout milliseconds for channel to receive a DTMF digit.
  791.     *
  792.     * @link http://www.voip-info.org/wiki-wait+for+digit
  793.     * @param integer $timeout in millisecons. Use -1 for the timeout value if you want the call to wait indefinitely.
  794.     * @return array, see evaluate for return information. ['result'] is 0 if wait completes with no
  795.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  796.     */
  797.     function wait_for_digit($timeout=-1)
  798.     {
  799.         return $this->evaluate("WAIT FOR DIGIT $timeout");
  800.     }
  801.  
  802.  
  803.     // *********************************************************************************************************
  804.     // **                             APPLICATIONS                                                                                        **
  805.     // *********************************************************************************************************
  806.  
  807.     /**
  808.     * Set absolute maximum time of call.
  809.     *
  810.     * Note that the timeout is set from the current time forward, not counting the number of seconds the call has already been up.
  811.     * Each time you call AbsoluteTimeout(), all previous absolute timeouts are cancelled.
  812.     * Will return the call to the T extension so that you can playback an explanatory note to the calling party (the called party
  813.     * will not hear that)
  814.     *
  815.     * @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands
  816.     * @link http://www.dynx.net/ASTERISK/AGI/ccard/agi-ccard.agi
  817.     * @param $seconds allowed, 0 disables timeout
  818.     * @return array, see evaluate for return information.
  819.     */
  820.     function exec_absolutetimeout($seconds=0)
  821.     {
  822.         return $this->exec('AbsoluteTimeout'$seconds);
  823.     }
  824.  
  825.     /**
  826.     * Executes an AGI compliant application.
  827.     *
  828.     * @param string $command 
  829.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or if application requested hangup, or 0 on non-hangup exit.
  830.     * @param string $args 
  831.     */
  832.     function exec_agi($command$args)
  833.     {
  834.         return $this->exec("AGI $command"$args);
  835.     }
  836.  
  837.     /**
  838.     * Set Language.
  839.     *
  840.     * @param string $language code
  841.     * @return array, see evaluate for return information.
  842.     */
  843.     function exec_setlanguage($language='en')
  844.     {
  845.         return $this->exec('Set''CHANNEL(language)='$language);
  846.     }
  847.  
  848.     /**
  849.     * Do ENUM Lookup.
  850.     *
  851.     * Note: to retrieve the result, use
  852.     *   get_variable('ENUM');
  853.     *
  854.     * @param $exten 
  855.     * @return array, see evaluate for return information.
  856.     */
  857.     function exec_enumlookup($exten)
  858.     {
  859.         return $this->exec('EnumLookup'$exten);
  860.     }
  861.  
  862.     /**
  863.     * Dial.
  864.     *
  865.     * Dial takes input from ${VXML_URL} to send XML Url to Cisco 7960
  866.     * Dial takes input from ${ALERT_INFO} to set ring cadence for Cisco phones
  867.     * Dial returns ${CAUSECODE}: If the dial failed, this is the errormessage.
  868.     * Dial returns ${DIALSTATUS}: Text code returning status of last dial attempt.
  869.     *
  870.     * @link http://www.voip-info.org/wiki-Asterisk+cmd+Dial
  871.     * @param string $type 
  872.     * @param string $identifier 
  873.     * @param integer $timeout 
  874.     * @param string $options 
  875.     * @param string $url 
  876.     * @return array, see evaluate for return information.
  877.     */
  878.     function exec_dial($type$identifier$timeout=NULL$options=NULL$url=NULL)
  879.     {
  880.         return $this->exec('Dial'trim("$type/$identifier".$this->option_delim.$timeout.$this->option_delim.$options.$this->option_delim.$url$this->option_delim));
  881.     }
  882.  
  883.     /**
  884.     * Goto.
  885.     *
  886.     * This function takes three arguments: context,extension, and priority, but the leading arguments
  887.     * are optional, not the trailing arguments.  Thuse goto($z) sets the priority to $z.
  888.     *
  889.     * @param string $a 
  890.     * @param string $b; 
  891.     * @param string $c; 
  892.     * @return array, see evaluate for return information.
  893.     */
  894.     function exec_goto($a$b=NULL$c=NULL)
  895.     {
  896.         return $this->exec('Goto'trim($a.$this->option_delim.$b.$this->option_delim.$c$this->option_delim));
  897.     }
  898.  
  899.  
  900.     // *********************************************************************************************************
  901.     // **                             FAST PASSING                                                                                        **
  902.     // *********************************************************************************************************
  903.  
  904.     /**
  905.     * Say the given digit string, returning early if any of the given DTMF escape digits are received on the channel.
  906.     * Return early if $buffer is adequate for request.
  907.     *
  908.     * @link http://www.voip-info.org/wiki-say+digits
  909.     * @param string $buffer 
  910.     * @param integer $digits 
  911.     * @param string $escape_digits 
  912.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  913.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  914.     */
  915.     function fastpass_say_digits(&$buffer$digits$escape_digits='')
  916.     {
  917.      $proceed false;
  918.      if($escape_digits != '' && $buffer != '')
  919.      {
  920.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  921.            $proceed true;
  922.      }
  923.      if($buffer == '' || $proceed)
  924.      {
  925.          $res $this->say_digits($digits$escape_digits);
  926.          if($res['code'== AGIRES_OK && $res['result'0)
  927.            $buffer .= chr($res['result']);
  928.          return $res;
  929.      }
  930.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1}));
  931.     }
  932.  
  933.     /**
  934.     * Say the given number, returning early if any of the given DTMF escape digits are received on the channel.
  935.     * Return early if $buffer is adequate for request.
  936.     *
  937.     * @link http://www.voip-info.org/wiki-say+number
  938.     * @param string $buffer 
  939.     * @param integer $number 
  940.     * @param string $escape_digits 
  941.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  942.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  943.     */
  944.     function fastpass_say_number(&$buffer$number$escape_digits='')
  945.     {
  946.      $proceed false;
  947.      if($escape_digits != '' && $buffer != '')
  948.      {
  949.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  950.            $proceed true;
  951.      }
  952.      if($buffer == '' || $proceed)
  953.      {
  954.          $res $this->say_number($number$escape_digits);
  955.          if($res['code'== AGIRES_OK && $res['result'0)
  956.            $buffer .= chr($res['result']);
  957.          return $res;
  958.      }
  959.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1}));
  960.     }
  961.  
  962.     /**
  963.     * Say the given character string, returning early if any of the given DTMF escape digits are received on the channel.
  964.     * Return early if $buffer is adequate for request.
  965.     *
  966.     * @link http://www.voip-info.org/wiki-say+phonetic
  967.     * @param string $buffer 
  968.     * @param string $text 
  969.     * @param string $escape_digits 
  970.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  971.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  972.     */
  973.     function fastpass_say_phonetic(&$buffer$text$escape_digits='')
  974.     {
  975.      $proceed false;
  976.      if($escape_digits != '' && $buffer != '')
  977.      {
  978.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  979.            $proceed true;
  980.      }
  981.      if($buffer == '' || $proceed)
  982.      {
  983.          $res $this->say_phonetic($text$escape_digits);
  984.          if($res['code'== AGIRES_OK && $res['result'0)
  985.            $buffer .= chr($res['result']);
  986.          return $res;
  987.      }
  988.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1}));
  989.     }
  990.  
  991.     /**
  992.     * Say a given time, returning early if any of the given DTMF escape digits are received on the channel.
  993.     * Return early if $buffer is adequate for request.
  994.     *
  995.     * @link http://www.voip-info.org/wiki-say+time
  996.     * @param string $buffer 
  997.     * @param integer $time number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).
  998.     * @param string $escape_digits 
  999.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  1000.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  1001.     */
  1002.     function fastpass_say_time(&$buffer$time=NULL$escape_digits='')
  1003.     {
  1004.      $proceed false;
  1005.      if($escape_digits != '' && $buffer != '')
  1006.      {
  1007.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  1008.            $proceed true;
  1009.      }
  1010.      if($buffer == '' || $proceed)
  1011.      {
  1012.          $res $this->say_time($time$escape_digits);
  1013.          if($res['code'== AGIRES_OK && $res['result'0)
  1014.            $buffer .= chr($res['result']);
  1015.          return $res;
  1016.      }
  1017.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1}));
  1018.     }
  1019.  
  1020.     /**
  1021.     * Play the given audio file, allowing playback to be interrupted by a DTMF digit. This command is similar to the GET DATA
  1022.     * command but this command returns after the first DTMF digit has been pressed while GET DATA can accumulated any number of
  1023.     * digits before returning.
  1024.     * Return early if $buffer is adequate for request.
  1025.     *
  1026.     * @link http://www.voip-info.org/wiki-stream+file
  1027.     * @param string $buffer 
  1028.     * @param string $filename without extension, often in /var/lib/asterisk/sounds
  1029.     * @param string $escape_digits 
  1030.     * @param integer $offset 
  1031.     * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
  1032.     *  digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
  1033.     */
  1034.     function fastpass_stream_file(&$buffer$filename$escape_digits=''$offset=0)
  1035.     {
  1036.      $proceed false;
  1037.      if($escape_digits != '' && $buffer != '')
  1038.      {
  1039.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  1040.            $proceed true;
  1041.      }
  1042.      if($buffer == '' || $proceed)
  1043.      {
  1044.          $res $this->stream_file($filename$escape_digits$offset);
  1045.          if($res['code'== AGIRES_OK && $res['result'0)
  1046.            $buffer .= chr($res['result']);
  1047.          return $res;
  1048.      }
  1049.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1})'endpos'=>0);
  1050.     }
  1051.  
  1052.     /**
  1053.     * Use festival to read text.
  1054.     * Return early if $buffer is adequate for request.
  1055.     *
  1056.     * @link http://www.cstr.ed.ac.uk/projects/festival/
  1057.     * @param string $buffer 
  1058.     * @param string $text 
  1059.     * @param string $escape_digits 
  1060.     * @param integer $frequency 
  1061.     * @return array, see evaluate for return information.
  1062.     */
  1063.     function fastpass_text2wav(&$buffer$text$escape_digits=''$frequency=8000)
  1064.     {
  1065.      $proceed false;
  1066.      if($escape_digits != '' && $buffer != '')
  1067.      {
  1068.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  1069.            $proceed true;
  1070.      }
  1071.      if($buffer == '' || $proceed)
  1072.      {
  1073.          $res $this->text2wav($text$escape_digits$frequency);
  1074.          if($res['code'== AGIRES_OK && $res['result'0)
  1075.            $buffer .= chr($res['result']);
  1076.          return $res;
  1077.      }
  1078.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1})'endpos'=>0);
  1079.     }
  1080.  
  1081.     /**
  1082.     * Use Cepstral Swift to read text.
  1083.     * Return early if $buffer is adequate for request.
  1084.     *
  1085.     * @link http://www.cepstral.com/
  1086.     * @param string $buffer 
  1087.     * @param string $text 
  1088.     * @param string $escape_digits 
  1089.     * @param integer $frequency 
  1090.     * @return array, see evaluate for return information.
  1091.     */
  1092.     function fastpass_swift(&$buffer$text$escape_digits=''$frequency=8000$voice=NULL)
  1093.     {
  1094.      $proceed false;
  1095.      if($escape_digits != '' && $buffer != '')
  1096.      {
  1097.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  1098.            $proceed true;
  1099.      }
  1100.      if($buffer == '' || $proceed)
  1101.      {
  1102.          $res $this->swift($text$escape_digits$frequency$voice);
  1103.          if($res['code'== AGIRES_OK && $res['result'0)
  1104.            $buffer .= chr($res['result']);
  1105.          return $res;
  1106.      }
  1107.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1})'endpos'=>0);
  1108.     }
  1109.  
  1110.     /**
  1111.     * Say Puncutation in a string.
  1112.     * Return early if $buffer is adequate for request.
  1113.     *
  1114.     * @param string $buffer 
  1115.     * @param string $text 
  1116.     * @param string $escape_digits 
  1117.     * @param integer $frequency 
  1118.     * @return array, see evaluate for return information.
  1119.     */
  1120.     function fastpass_say_punctuation(&$buffer$text$escape_digits=''$frequency=8000)
  1121.     {
  1122.      $proceed false;
  1123.      if($escape_digits != '' && $buffer != '')
  1124.      {
  1125.          if(!strpos(chr(255$escape_digits$buffer{strlen($buffer)-1}))
  1126.            $proceed true;
  1127.      }
  1128.      if($buffer == '' || $proceed)
  1129.      {
  1130.          $res $this->say_punctuation($text$escape_digits$frequency);
  1131.          if($res['code'== AGIRES_OK && $res['result'0)
  1132.            $buffer .= chr($res['result']);
  1133.          return $res;
  1134.      }
  1135.      return array('code'=>AGIRES_OK'result'=>ord($buffer{strlen($buffer)-1}));
  1136.     }
  1137.  
  1138.     /**
  1139.     * Plays the given file and receives DTMF data.
  1140.     * Return early if $buffer is adequate for request.
  1141.     *
  1142.     * This is similar to STREAM FILE, but this command can accept and return many DTMF digits,
  1143.     * while STREAM FILE returns immediately after the first DTMF digit is detected.
  1144.     *
  1145.     * Asterisk looks for the file to play in /var/lib/asterisk/sounds by default.
  1146.     *
  1147.     * If the user doesn't press any keys when the message plays, there is $timeout milliseconds
  1148.     * of silence then the command ends.
  1149.     *
  1150.     * The user has the opportunity to press a key at any time during the message or the
  1151.     * post-message silence. If the user presses a key while the message is playing, the
  1152.     * message stops playing. When the first key is pressed a timer starts counting for
  1153.     * $timeout milliseconds. Every time the user presses another key the timer is restarted.
  1154.     * The command ends when the counter goes to zero or the maximum number of digits is entered,
  1155.     * whichever happens first.
  1156.     *
  1157.     * If you don't specify a time out then a default timeout of 2000 is used following a pressed
  1158.     * digit. If no digits are pressed then 6 seconds of silence follow the message.
  1159.     *
  1160.     * If you don't specify $max_digits then the user can enter as many digits as they want.
  1161.     *
  1162.     * Pressing the # key has the same effect as the timer running out: the command ends and
  1163.     * any previously keyed digits are returned. A side effect of this is that there is no
  1164.     * way to read a # key using this command.
  1165.     *
  1166.     * @link http://www.voip-info.org/wiki-get+data
  1167.     * @param string $buffer 
  1168.     * @param string $filename file to play. Do not include file extension.
  1169.     * @param integer $timeout milliseconds
  1170.     * @param integer $max_digits 
  1171.     * @return array, see evaluate for return information. ['result'] holds the digits and ['data'] holds the timeout if present.
  1172.     *
  1173.     *  This differs from other commands with return DTMF as numbers representing ASCII characters.
  1174.     */
  1175.     function fastpass_get_data(&$buffer$filename$timeout=NULL$max_digits=NULL)
  1176.     {
  1177.      if(is_null($max_digits|| strlen($buffer$max_digits)
  1178.      {
  1179.          if($buffer == '')
  1180.          {
  1181.            $res $this->get_data($filename$timeout$max_digits);
  1182.            if($res['code'== AGIRES_OK)
  1183.              $buffer .= $res['result'];
  1184.            return $res;
  1185.          }
  1186.          else
  1187.          {
  1188.            while(is_null($max_digits|| strlen($buffer$max_digits)
  1189.            {
  1190.              $res $this->wait_for_digit();
  1191.              if($res['code'!= AGIRES_OKreturn $res;
  1192.              if($res['result'== ord('#')) break;
  1193.              $buffer .= chr($res['result']);
  1194.            }
  1195.          }
  1196.      }
  1197.      return array('code'=>AGIRES_OK'result'=>$buffer);
  1198.     }
  1199.  
  1200.     // *********************************************************************************************************
  1201.     // **                             DERIVED                                                                                             **
  1202.     // *********************************************************************************************************
  1203.  
  1204.     /**
  1205.     * Menu.
  1206.     *
  1207.     * This function presents the user with a menu and reads the response
  1208.     *
  1209.     * @param array $choices has the following structure:
  1210.     *    array('1'=>'*Press 1 for this', // festival reads if prompt starts with *
  1211.     *            '2'=>'some-gsm-without-extension',
  1212.     *            '*'=>'*Press star for help');
  1213.     * @return mixed key pressed on sucess, -1 on failure
  1214.     */
  1215.     function menu($choices$timeout=2000)
  1216.     {
  1217.         $keys join(''array_keys($choices));
  1218.         $choice NULL;
  1219.         while(is_null($choice))
  1220.         {
  1221.           foreach($choices as $prompt)
  1222.           {
  1223.             if($prompt{0== '*')
  1224.                 $ret $this->text2wav(substr($prompt1)$keys);
  1225.             else
  1226.                 $ret $this->stream_file($prompt$keys);
  1227.  
  1228.             if($ret['code'!= AGIRES_OK || $ret['result'== -1)
  1229.             {
  1230.                 $choice = -1;
  1231.                 break;
  1232.             }
  1233.  
  1234.             if($ret['result'!= 0)
  1235.             {
  1236.                 $choice chr($ret['result']);
  1237.                 break;
  1238.             }
  1239.           }
  1240.  
  1241.           if(is_null($choice))
  1242.           {
  1243.             $ret $this->get_data('beep'$timeout1);
  1244.             if($ret['code'!= AGIRES_OK || $ret['result'== -1)
  1245.                 $choice = -1;
  1246.             elseif($ret['result'!= '' && strpos(' '.$keys$ret['result']))
  1247.                 $choice $ret['result'];
  1248.           }
  1249.         }
  1250.         return $choice;
  1251.     }
  1252.  
  1253.     /**
  1254.     * setContext - Set context, extension and priority.
  1255.     *
  1256.     * @param string $context 
  1257.     * @param string $extension 
  1258.     * @param string $priority 
  1259.     */
  1260.     function setContext($context$extension='s'$priority=1)
  1261.     {
  1262.         $this->set_context($context);
  1263.         $this->set_extension($extension);
  1264.         $this->set_priority($priority);
  1265.     }
  1266.  
  1267.     /**
  1268.     * Parse caller id.
  1269.     *
  1270.     * @example examples/dtmf.php Get DTMF tones from the user and say the digits
  1271.     * @example examples/input.php Get text input from the user and say it back
  1272.     *
  1273.     *  "name" <proto:user@server:port>
  1274.     *
  1275.     * @param string $callerid 
  1276.     * @return array('Name'=>$name, 'Number'=>$number)
  1277.     */
  1278.     function parse_callerid($callerid=NULL)
  1279.     {
  1280.         if(is_null($callerid))
  1281.           $callerid $this->request['agi_callerid'];
  1282.  
  1283.         $ret array('name'=>'''protocol'=>'''username'=>'''host'=>'''port'=>'');
  1284.         $callerid trim($callerid);
  1285.  
  1286.         if($callerid{0== '"' || $callerid{0== "'")
  1287.         {
  1288.           $d $callerid{0};
  1289.           $callerid explode($dsubstr($callerid1));
  1290.           $ret['name'array_shift($callerid);
  1291.           $callerid join($d$callerid);
  1292.         }
  1293.  
  1294.         $callerid explode('@'trim($callerid'<> '));
  1295.         $username  explode(':'array_shift($callerid));
  1296.         if(count($username== 1)
  1297.           $ret['username'$username[0];
  1298.         else
  1299.         {
  1300.           $ret['protocol'array_shift($username);
  1301.           $ret['username'join(':'$username);
  1302.         }
  1303.  
  1304.         $callerid join('@'$callerid);
  1305.         $host explode(':'$callerid);
  1306.         if(count($host== 1)
  1307.           $ret['host'=  $host[0];
  1308.         else
  1309.         {
  1310.           $ret['host'array_shift($host);
  1311.           $ret['port'join(':'$host);
  1312.         }
  1313.  
  1314.         return $ret;
  1315.     }
  1316.  
  1317.     /**
  1318.     * Use festival to read text.
  1319.     *
  1320.     * @example examples/dtmf.php Get DTMF tones from the user and say the digits
  1321.     * @example examples/input.php Get text input from the user and say it back
  1322.     * @example examples/ping.php Ping an IP address
  1323.     *
  1324.     * @link http://www.cstr.ed.ac.uk/projects/festival/
  1325.     * @param string $text 
  1326.     * @param string $escape_digits 
  1327.     * @param integer $frequency 
  1328.     * @return array, see evaluate for return information.
  1329.     */
  1330.     function text2wav($text$escape_digits=''$frequency=8000)
  1331.     {
  1332.         $text trim($text);
  1333.         if($text == ''return true;
  1334.  
  1335.         $hash md5($text);
  1336.         $fname $this->config['phpagi']['tempdir'DIRECTORY_SEPARATOR;
  1337.         $fname .= 'text2wav_' $hash;
  1338.  
  1339.         // create wave file
  1340.         if(!file_exists("$fname.wav"))
  1341.         {
  1342.           // write text file
  1343.           if(!file_exists("$fname.txt"))
  1344.           {
  1345.             $fp fopen("$fname.txt"'w');
  1346.             fputs($fp$text);
  1347.             fclose($fp);
  1348.           }
  1349.  
  1350.           shell_exec("{$this->config['festival']['text2wave']} -F $frequency -o $fname.wav $fname.txt");
  1351.         }
  1352.         else
  1353.         {
  1354.           touch("$fname.txt");
  1355.           touch("$fname.wav");
  1356.         }
  1357.  
  1358.         // stream it
  1359.         $ret $this->stream_file($fname$escape_digits);
  1360.  
  1361.         // clean up old files
  1362.         $delete time(2592000// 1 month
  1363.         foreach(glob($this->config['phpagi']['tempdir'DIRECTORY_SEPARATOR 'text2wav_*'as $file)
  1364.           if(filemtime($file$delete)
  1365.             unlink($file);
  1366.  
  1367.         return $ret;
  1368.     }
  1369.  
  1370.     /**
  1371.     * Use Cepstral Swift to read text.
  1372.     *
  1373.     * @link http://www.cepstral.com/
  1374.     * @param string $text 
  1375.     * @param string $escape_digits 
  1376.     * @param integer $frequency 
  1377.     * @return array, see evaluate for return information.
  1378.     */
  1379.     function swift($text$escape_digits=''$frequency=8000$voice=NULL)
  1380.     {
  1381.         if(!is_null($voice))
  1382.           $voice "-n $voice";
  1383.         elseif(isset($this->config['cepstral']['voice']))
  1384.           $voice "-n {$this->config['cepstral']['voice']}";
  1385.  
  1386.         $text trim($text);
  1387.         if($text == ''return true;
  1388.  
  1389.         $hash md5($text);
  1390.         $fname $this->config['phpagi']['tempdir'DIRECTORY_SEPARATOR;
  1391.         $fname .= 'swift_' $hash;
  1392.  
  1393.         // create wave file
  1394.         if(!file_exists("$fname.wav"))
  1395.         {
  1396.           // write text file
  1397.           if(!file_exists("$fname.txt"))
  1398.           {
  1399.             $fp fopen("$fname.txt"'w');
  1400.             fputs($fp$text);
  1401.             fclose($fp);
  1402.           }
  1403.  
  1404.           shell_exec("{$this->config['cepstral']['swift']} -p audio/channels=1,audio/sampling-rate=$frequency $voice -o $fname.wav -f $fname.txt");
  1405.         }
  1406.  
  1407.         // stream it
  1408.         $ret $this->stream_file($fname$escape_digits);
  1409.  
  1410.         // clean up old files
  1411.         $delete time(2592000// 1 month
  1412.         foreach(glob($this->config['phpagi']['tempdir'DIRECTORY_SEPARATOR 'swift_*'as $file)
  1413.           if(filemtime($file$delete)
  1414.             unlink($file);
  1415.  
  1416.         return $ret;
  1417.     }
  1418.  
  1419.     /**
  1420.     * Text Input.
  1421.     *
  1422.     * Based on ideas found at http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText
  1423.     *
  1424.     * Example:
  1425.     *                  UC   H     LC   i        ,     SP   h     o        w    SP   a    r        e     SP   y        o        u     ?
  1426.     *   $string = '*8'.'44*'.'*5'.'444*'.'00*'.'0*'.'44*'.'666*'.'9*'.'0*'.'2*'.'777*'.'33*'.'0*'.'999*'.'666*'.'88*'.'0000*';
  1427.     *
  1428.     * @link http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText
  1429.     * @example examples/input.php Get text input from the user and say it back
  1430.     *
  1431.     * @return string 
  1432.     */
  1433.     function text_input($mode='NUMERIC')
  1434.     {
  1435.         $alpha array'k0'=>' ''k00'=>',''k000'=>'.''k0000'=>'?''k00000'=>'0',
  1436.                             'k1'=>'!''k11'=>':''k111'=>';''k1111'=>'#''k11111'=>'1',
  1437.                             'k2'=>'A''k22'=>'B''k222'=>'C''k2222'=>'2',
  1438.                             'k3'=>'D''k33'=>'E''k333'=>'F''k3333'=>'3',
  1439.                             'k4'=>'G''k44'=>'H''k444'=>'I''k4444'=>'4',
  1440.                             'k5'=>'J''k55'=>'K''k555'=>'L''k5555'=>'5',
  1441.                             'k6'=>'M''k66'=>'N''k666'=>'O''k6666'=>'6',
  1442.                             'k7'=>'P''k77'=>'Q''k777'=>'R''k7777'=>'S''k77777'=>'7',
  1443.                             'k8'=>'T''k88'=>'U''k888'=>'V''k8888'=>'8',
  1444.                             'k9'=>'W''k99'=>'X''k999'=>'Y''k9999'=>'Z''k99999'=>'9');
  1445.         $symbol array('k0'=>'=',
  1446.                             'k1'=>'<''k11'=>'(''k111'=>'[''k1111'=>'{''k11111'=>'1',
  1447.                             'k2'=>'@''k22'=>'$''k222'=>'&''k2222'=>'%''k22222'=>'2',
  1448.                             'k3'=>'>''k33'=>')''k333'=>']''k3333'=>'}''k33333'=>'3',
  1449.                             'k4'=>'+''k44'=>'-''k444'=>'*''k4444'=>'/''k44444'=>'4',
  1450.                             'k5'=>"'"'k55'=>'`''k555'=>'5',
  1451.                             'k6'=>'"''k66'=>'6',
  1452.                             'k7'=>'^''k77'=>'7',
  1453.                             'k8'=>"\\",'k88'=>'|''k888'=>'8',
  1454.                             'k9'=>'_''k99'=>'~''k999'=>'9');
  1455.         $text '';
  1456.         do
  1457.         {
  1458.           $command false;
  1459.           $result $this->get_data('beep');
  1460.           foreach(explode('*'$result['result']as $code)
  1461.           {
  1462.             if($command)
  1463.             {
  1464.                 switch($code{0})
  1465.                 {
  1466.                   case '2'$text substr($text0strlen($text1)break// backspace
  1467.                   case '5'$mode 'LOWERCASE'break;
  1468.                   case '6'$mode 'NUMERIC'break;
  1469.                   case '7'$mode 'SYMBOL'break;
  1470.                   case '8'$mode 'UPPERCASE'break;
  1471.                   case '9'$text explode(' '$text)unset($text[count($text)-1])$text join(' '$text)break// backspace a word
  1472.                 }
  1473.                 $code substr($code1);
  1474.                 $command false;
  1475.             }
  1476.             if($code == '')
  1477.                 $command true;
  1478.             elseif($mode == 'NUMERIC')
  1479.                 $text .= $code;
  1480.             elseif($mode == 'UPPERCASE' && isset($alpha['k'.$code]))
  1481.                 $text .= $alpha['k'.$code];
  1482.             elseif($mode == 'LOWERCASE' && isset($alpha['k'.$code]))
  1483.                 $text .= strtolower($alpha['k'.$code]);
  1484.             elseif($mode == 'SYMBOL' && isset($symbol['k'.$code]))
  1485.                 $text .= $symbol['k'.$code];
  1486.           }
  1487.           $this->say_punctuation($text);
  1488.         while(substr($result['result']-2== '**');
  1489.         return $text;
  1490.     }
  1491.  
  1492.     /**
  1493.     * Say Puncutation in a string.
  1494.     *
  1495.     * @param string $text 
  1496.     * @param string $escape_digits 
  1497.     * @param integer $frequency 
  1498.     * @return array, see evaluate for return information.
  1499.     */
  1500.     function say_punctuation($text$escape_digits=''$frequency=8000)
  1501.     {
  1502.         $ret="";
  1503.         for($i 0$i strlen($text)$i++)
  1504.         {
  1505.           switch($text{$i})
  1506.           {
  1507.             case ' '$ret .= 'SPACE ';
  1508.             case ','$ret .= 'COMMA 'break;
  1509.             case '.'$ret .= 'PERIOD 'break;
  1510.             case '?'$ret .= 'QUESTION MARK 'break;
  1511.             case '!'$ret .= 'EXPLANATION POINT 'break;
  1512.             case ':'$ret .= 'COLON 'break;
  1513.             case ';'$ret .= 'SEMICOLON 'break;
  1514.             case '#'$ret .= 'POUND 'break;
  1515.             case '='$ret .= 'EQUALS 'break;
  1516.             case '<'$ret .= 'LESS THAN 'break;
  1517.             case '('$ret .= 'LEFT PARENTHESIS 'break;
  1518.             case '['$ret .= 'LEFT BRACKET 'break;
  1519.             case '{'$ret .= 'LEFT BRACE 'break;
  1520.             case '@'$ret .= 'AT 'break;
  1521.             case '$'$ret .= 'DOLLAR SIGN 'break;
  1522.             case '&'$ret .= 'AMPERSAND 'break;
  1523.             case '%'$ret .= 'PERCENT 'break;
  1524.             case '>'$ret .= 'GREATER THAN 'break;
  1525.             case ')'$ret .= 'RIGHT PARENTHESIS 'break;
  1526.             case ']'$ret .= 'RIGHT BRACKET 'break;
  1527.             case '}'$ret .= 'RIGHT BRACE 'break;
  1528.             case '+'$ret .= 'PLUS 'break;
  1529.             case '-'$ret .= 'MINUS 'break;
  1530.             case '*'$ret .= 'ASTERISK 'break;
  1531.             case '/'$ret .= 'SLASH 'break;
  1532.             case "'"$ret .= 'SINGLE QUOTE 'break;
  1533.             case '`'$ret .= 'BACK TICK 'break;
  1534.             case '"'$ret .= 'QUOTE 'break;
  1535.             case '^'$ret .= 'CAROT 'break;
  1536.             case "\\"$ret .= 'BACK SLASH 'break;
  1537.             case '|'$ret .= 'BAR 'break;
  1538.             case '_'$ret .= 'UNDERSCORE 'break;
  1539.             case '~'$ret .= 'TILDE 'break;
  1540.             default$ret .= $text{$i' 'break;
  1541.           }
  1542.         }
  1543.         return $this->text2wav($ret$escape_digits$frequency);
  1544.     }
  1545.  
  1546.     /**
  1547.     * Create a new AGI_AsteriskManager.
  1548.     */
  1549.     function &new_AsteriskManager()
  1550.     {
  1551.         $this->asm new AGI_AsteriskManager(NULL$this->config);
  1552.         $this->asm->pagi =$this;
  1553.         $this->config =$this->asm->config;
  1554.         return $this->asm;
  1555.     }
  1556.  
  1557.  
  1558.     // *********************************************************************************************************
  1559.     // **                             PRIVATE                                                                                             **
  1560.     // *********************************************************************************************************
  1561.  
  1562.  
  1563.     /**
  1564.     * Evaluate an AGI command.
  1565.     *
  1566.     * @access private
  1567.     * @param string $command 
  1568.     * @return array ('code'=>$code, 'result'=>$result, 'data'=>$data)
  1569.     */
  1570.     function evaluate($command)
  1571.     {
  1572.         $broken array('code'=>500'result'=>-1'data'=>'');
  1573.  
  1574.         // write command
  1575.         if(!@fwrite($this->outtrim($command"\n")) return $broken;
  1576.         fflush($this->out);
  1577.  
  1578.         // Read result.  Occasionally, a command return a string followed by an extra new line.
  1579.         // When this happens, our script will ignore the new line, but it will still be in the
  1580.         // buffer.  So, if we get a blank line, it is probably the result of a previous
  1581.         // command.  We read until we get a valid result or asterisk hangs up.  One offending
  1582.         // command is SEND TEXT.
  1583.         $count 0;
  1584.         do
  1585.         {
  1586.           $str trim(fgets($this->in4096));
  1587.         while($str == '' && $count++ < 5);
  1588.  
  1589.         if($count >= 5)
  1590.         {
  1591.     //          $this->conlog("evaluate error on read for $command");
  1592.           return $broken;
  1593.         }
  1594.  
  1595.         // parse result
  1596.         $ret['code'substr($str03);
  1597.         $str trim(substr($str3));
  1598.  
  1599.         if($str{0== '-'// we have a multiline response!
  1600.         {
  1601.           $count 0;
  1602.           $str substr($str1"\n";
  1603.           $line fgets($this->in4096);
  1604.           while(substr($line03!= $ret['code'&& $count 5)
  1605.           {
  1606.             $str .= $line;
  1607.             $line fgets($this->in4096);
  1608.             $count (trim($line== ''$count 0;
  1609.           }
  1610.           if($count >= 5)
  1611.           {
  1612.     //            $this->conlog("evaluate error on multiline read for $command");
  1613.             return $broken;
  1614.           }
  1615.         }
  1616.  
  1617.         $ret['result'NULL;
  1618.         $ret['data''';
  1619.         if($ret['code'!= AGIRES_OK// some sort of error
  1620.         {
  1621.           $ret['data'$str;
  1622.           $this->conlog(print_r($rettrue));
  1623.         }
  1624.         else // normal AGIRES_OK response
  1625.         {
  1626.           $parse explode(' 'trim($str));
  1627.           $in_token false;
  1628.           foreach($parse as $token)
  1629.           {
  1630.             if($in_token// we previously hit a token starting with ')' but not ending in ')'
  1631.             {
  1632.                 $ret['data'.= ' ' trim($token'() ');
  1633.                 if($token{strlen($token)-1== ')'$in_token false;
  1634.             }
  1635.             elseif($token{0== '(')
  1636.             {
  1637.                 if($token{strlen($token)-1!= ')'$in_token true;
  1638.                 $ret['data'.= ' ' trim($token'() ');
  1639.             }
  1640.             elseif(strpos($token'='))
  1641.             {
  1642.                 $token explode('='$token);
  1643.                 $ret[$token[0]] $token[1];
  1644.             }
  1645.             elseif($token != '')
  1646.                 $ret['data'.= ' ' $token;
  1647.           }
  1648.           $ret['data'trim($ret['data']);
  1649.         }
  1650.  
  1651.         // log some errors
  1652.         if($ret['result'0)
  1653.           $this->conlog("$command returned {$ret['result']}");
  1654.  
  1655.         return $ret;
  1656.     }
  1657.  
  1658.     /**
  1659.     * Log to console if debug mode.
  1660.     *
  1661.     * @example examples/ping.php Ping an IP address
  1662.     *
  1663.     * @param string $str 
  1664.     * @param integer $vbl verbose level
  1665.     */
  1666.     function conlog($str$vbl=1)
  1667.     {
  1668.         static $busy false;
  1669.  
  1670.         if($this->config['phpagi']['debug'!= false)
  1671.         {
  1672.           if(!$busy// no conlogs inside conlog!!!
  1673.           {
  1674.             $busy true;
  1675.             $this->verbose($str$vbl);
  1676.             $busy false;
  1677.           }
  1678.         }
  1679.     }
  1680.  
  1681.     /**
  1682.     * Find an execuable in the path.
  1683.     *
  1684.     * @access private
  1685.     * @param string $cmd command to find
  1686.     * @param string $checkpath path to check
  1687.     * @return string the path to the command
  1688.     */
  1689.     function which($cmd$checkpath=NULL)
  1690.     {
  1691.         global $_ENV;
  1692.         $chpath is_null($checkpath$_ENV['PATH'$checkpath;
  1693.  
  1694.         foreach(explode(':'$chpathas $path)
  1695.           if(is_executable("$path/$cmd"))
  1696.             return "$path/$cmd";
  1697.  
  1698.         if(is_null($checkpath))
  1699.           return $this->which($cmd'/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:'.
  1700.                                             '/usr/X11R6/bin:/usr/local/apache/bin:/usr/local/mysql/bin');
  1701.         return false;
  1702.     }
  1703.  
  1704.     /**
  1705.     * Make a folder recursively.
  1706.     *
  1707.     * @access private
  1708.     * @param string $folder 
  1709.     * @param integer $perms 
  1710.     * @return boolean 
  1711.     */
  1712.     function make_folder($folder$perms=0755)
  1713.     {
  1714.         $f explode(DIRECTORY_SEPARATOR$folder);
  1715.         $base '';
  1716.         for($i 0$i count($f)$i++)
  1717.         {
  1718.           $base .= $f[$i];
  1719.           if($f[$i!= '' && !file_exists($base)) {
  1720.             if(mkdir($base$perms)==FALSE){
  1721.               return(FALSE);
  1722.             }
  1723.           }
  1724.           $base .= DIRECTORY_SEPARATOR;
  1725.         }
  1726.         return(TRUE);
  1727.     }    
  1728.  
  1729. }
  1730.  
  1731.  
  1732. /**
  1733.  * error handler for phpagi.
  1734.  *
  1735.  * @param integer $level PHP error level
  1736.  * @param string $message error message
  1737.  * @param string $file path to file
  1738.  * @param integer $line line number of error
  1739.  * @param array $context variables in the current scope
  1740.  */
  1741.   function phpagi_error_handler($level$message$file$line$context)
  1742.   {
  1743.     if(ini_get('error_reporting'== 0return// this happens with an @
  1744.  
  1745.     @syslog(LOG_WARNING$file '[' $line ']: ' $message);
  1746.  
  1747.     global $phpagi_error_handler_email;
  1748.     if(function_exists('mail'&& !is_null($phpagi_error_handler_email)) // generate email debugging information
  1749.     {
  1750.         // decode error level
  1751.         switch($level)
  1752.         {
  1753.           case E_WARNING:
  1754.           case E_USER_WARNING:
  1755.             $level "Warning";
  1756.             break;
  1757.           case E_NOTICE:
  1758.           case E_USER_NOTICE:
  1759.             $level "Notice";
  1760.             break;
  1761.           case E_USER_ERROR:
  1762.             $level "Error";
  1763.             break;
  1764.         }
  1765.  
  1766.         // build message
  1767.         $basefile basename($file);
  1768.         $subject "$basefile/$line/$level$message";
  1769.         $message "$level$message in $file on line $line\n\n";
  1770.  
  1771.         if(function_exists('mysql_errno'&& strpos(' '.strtolower($message)'mysql'))
  1772.           $message .= 'MySQL error ' mysql_errno(": " mysql_error("\n\n";
  1773.  
  1774.         // figure out who we are
  1775.         if(function_exists('socket_create'))
  1776.         {
  1777.           $addr NULL;
  1778.           $port 80;
  1779.           $socket @socket_create(AF_INETSOCK_DGRAMSOL_UDP);
  1780.           @socket_connect($socket'64.0.0.0'$port);
  1781.           @socket_getsockname($socket$addr$port);
  1782.           @socket_close($socket);
  1783.           $message .= "\n\nIP Address: $addr\n";
  1784.         }
  1785.  
  1786.         // include variables
  1787.         $message .= "\n\nContext:\n" print_r($contexttrue);
  1788.         $message .= "\n\nGLOBALS:\n" print_r($GLOBALStrue);
  1789.         $message .= "\n\nBacktrace:\n" print_r(debug_backtrace()true);
  1790.  
  1791.         // include code fragment
  1792.         if(file_exists($file))
  1793.         {
  1794.           $message .= "\n\n$file:\n";
  1795.           $code @file($file);
  1796.           for($i max(0$line 10)$i min($line 10count($code))$i++)
  1797.             $message .= ($i 1)."\t$code[$i]";
  1798.         }
  1799.  
  1800.         // make sure message is fully readable (convert unprintable chars to hex representation)
  1801.         $ret '';
  1802.         for($i 0$i strlen($message)$i++)
  1803.         {
  1804.           $c ord($message{$i});
  1805.           if($c == 10 || $c == 13 || $c == 9)
  1806.             $ret .= $message{$i};
  1807.           elseif($c 16)
  1808.             $ret .= '\x0' dechex($c);
  1809.           elseif($c 32 || $c 127)
  1810.             $ret .= '\x' dechex($c);
  1811.           else
  1812.             $ret .= $message{$i};
  1813.         }
  1814.         $message $ret;
  1815.  
  1816.         // send the mail if less than 5 errors
  1817.         static $mailcount 0;
  1818.         if($mailcount 5)
  1819.           @mail($phpagi_error_handler_email$subject$message);
  1820.         $mailcount++;
  1821.     }
  1822.   }
  1823.  
  1824.   $phpagi_error_handler_email NULL;

Documentation generated on Thu, 30 Sep 2010 02:21:59 -0700 by phpDocumentor 1.4.2