📄 phpagi.php
字号:
<?php
/**
* phpagi.php : PHP AGI Functions for Asterisk
* Website: http://phpagi.sourceforge.net/
*
* $Id: phpagi.php,v 2.14 2005/05/25 20:30:46 pinhole Exp $
*
* Copyright (c) 2003, 2004, 2005 Matthew Asham <matthewa@bcwireless.net>, David Eder <david@eder.us>
* All Rights Reserved.
*
* This software is released under the terms of the GNU Lesser General Public License v2.1
* A copy of which is available from http://www.gnu.org/copyleft/lesser.html
*
* We would be happy to list your phpagi based application on the phpagi
* website. Drop me an Email if you'd like us to list your program.
*
*
* Written for PHP 4.3.4, should work with older PHP 4.x versions.
*
* Please submit bug reports, patches, etc to http://sourceforge.net/projects/phpagi/
* Gracias. :)
*
*
* @package phpAGI
* @version 2.0
*/
/**
*/
if(!class_exists('AGI_AsteriskManager'))
{
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'phpagi-asmanager.php');
}
define('AST_CONFIG_DIR', '/etc/asterisk/');
define('AST_SPOOL_DIR', '/var/spool/asterisk/');
define('AST_TMP_DIR', AST_SPOOL_DIR . '/tmp/');
define('DEFAULT_PHPAGI_CONFIG', AST_CONFIG_DIR . '/phpagi.conf');
define('AST_DIGIT_ANY', '0123456789#*');
define('AGIRES_OK', 200);
define('AST_STATE_DOWN', 0);
define('AST_STATE_RESERVED', 1);
define('AST_STATE_OFFHOOK', 2);
define('AST_STATE_DIALING', 3);
define('AST_STATE_RING', 4);
define('AST_STATE_RINGING', 5);
define('AST_STATE_UP', 6);
define('AST_STATE_BUSY', 7);
define('AST_STATE_DIALING_OFFHOOK', 8);
define('AST_STATE_PRERING', 9);
define('AUDIO_FILENO', 3); // STDERR_FILENO + 1
/**
* AGI class
*
* @package phpAGI
* @link http://www.voip-info.org/wiki-Asterisk+agi
* @example examples/dtmf.php Get DTMF tones from the user and say the digits
* @example examples/input.php Get text input from the user and say it back
* @example examples/ping.php Ping an IP address
*/
class AGI
{
/**
* Request variables read in on initialization.
*
* Often contains any/all of the following:
* agi_request - name of agi script
* agi_channel - current channel
* agi_language - current language
* agi_type - channel type (SIP, ZAP, IAX, ...)
* agi_uniqueid - unique id based on unix time
* agi_callerid - callerID string
* agi_dnid - dialed number id
* agi_rdnis - referring DNIS number
* agi_context - current context
* agi_extension - extension dialed
* agi_priority - current priority
* agi_enhanced - value is 1.0 if started as an EAGI script
* agi_accountcode - set by SetAccount in the dialplan
* agi_network - value is yes if this is a fastagi
* agi_network_script - name of the script to execute
*
* NOTE: program arguments are still in $_SERVER['argv'].
*
* @var array
* @access public
*/
var $request;
/**
* Config variables
*
* @var array
* @access public
*/
var $config;
/**
* Asterisk Manager
*
* @var AGI_AsteriskManager
* @access public
*/
var $asmanager;
/**
* Input Stream
*
* @access private
*/
var $in = NULL;
/**
* Output Stream
*
* @access private
*/
var $out = NULL;
/**
* Audio Stream
*
* @access public
*/
var $audio = NULL;
/**
* Constructor
*
* @param string $config is the name of the config file to parse
* @param array $optconfig is an array of configuration vars and vals, stuffed into $this->config['phpagi']
*/
function AGI($config=NULL, $optconfig=array())
{
// load config
if(!is_null($config) && file_exists($config))
$this->config = parse_ini_file($config, true);
elseif(file_exists(DEFAULT_PHPAGI_CONFIG))
$this->config = parse_ini_file(DEFAULT_PHPAGI_CONFIG, true);
// If optconfig is specified, stuff vals and vars into 'phpagi' config array.
foreach($optconfig as $var=>$val)
$this->config['phpagi'][$var] = $val;
// add default values to config for uninitialized values
if(!isset($this->config['phpagi']['error_handler'])) $this->config['phpagi']['error_handler'] = true;
if(!isset($this->config['phpagi']['debug'])) $this->config['phpagi']['debug'] = false;
if(!isset($this->config['phpagi']['admin'])) $this->config['phpagi']['admin'] = NULL;
if(!isset($this->config['phpagi']['tempdir'])) $this->config['phpagi']['tempdir'] = AST_TMP_DIR;
// festival TTS config
if(!isset($this->config['festival']['text2wave'])) $this->config['festival']['text2wave'] = $this->which('text2wave');
// swift TTS config
if(!isset($this->config['cepstral']['swift'])) $this->config['cepstral']['swift'] = $this->which('swift');
ob_implicit_flush(true);
// open stdin & stdout
$this->in = defined('STDIN') ? STDIN : fopen('php://stdin', 'r');
$this->out = defined('STDOUT') ? STDOUT : fopen('php://stdout', 'w');
// initialize error handler
if($this->config['phpagi']['error_handler'] == true)
{
set_error_handler('phpagi_error_handler');
global $phpagi_error_handler_email;
$phpagi_error_handler_email = $this->config['phpagi']['admin'];
error_reporting(E_ALL);
}
// make sure temp folder exists
$this->make_folder($this->config['phpagi']['tempdir']);
// read the request
$str = fgets($this->in);
while($str != "\n")
{
$this->request[substr($str, 0, strpos($str, ':'))] = trim(substr($str, strpos($str, ':') + 1));
$str = fgets($this->in);
}
// open audio if eagi detected
if($this->request['agi_enhanced'] == '1.0')
{
if(file_exists('/proc/' . getmypid() . '/fd/3'))
$this->audio = fopen('/proc/' . getmypid() . '/fd/3', 'r');
elseif(file_exists('/dev/fd/3'))
{
// may need to mount fdescfs
$this->audio = fopen('/dev/fd/3', 'r');
}
else
$this->conlog('Unable to open audio stream');
if($this->audio) stream_set_blocking($this->audio, 0);
}
$this->conlog('AGI Request:');
$this->conlog(print_r($this->request, true));
$this->conlog('PHPAGI internal configuration:');
$this->conlog(print_r($this->config, true));
}
// *********************************************************************************************************
// ** COMMANDS **
// *********************************************************************************************************
/**
* Answer channel if not already in answer state.
*
* @link http://www.voip-info.org/wiki-answer
* @example examples/dtmf.php Get DTMF tones from the user and say the digits
* @example examples/input.php Get text input from the user and say it back
* @example examples/ping.php Ping an IP address
*
* @return array, see evaluate for return information. ['result'] is 0 on success, -1 on failure.
*/
function answer()
{
return $this->evaluate('ANSWER');
}
/**
* Get the status of the specified channel. If no channel name is specified, return the status of the current channel.
*
* @link http://www.voip-info.org/wiki-channel+status
* @param string $channel
* @return array, see evaluate for return information. ['data'] contains description.
*/
function channel_status($channel='')
{
$ret = $this->evaluate("CHANNEL STATUS $channel");
switch($ret['result'])
{
case -1: $ret['data'] = trim("There is no channel that matches $channel"); break;
case AST_STATE_DOWN: $ret['data'] = 'Channel is down and available'; break;
case AST_STATE_RESERVED: $ret['data'] = 'Channel is down, but reserved'; break;
case AST_STATE_OFFHOOK: $ret['data'] = 'Channel is off hook'; break;
case AST_STATE_DIALING: $ret['data'] = 'Digits (or equivalent) have been dialed'; break;
case AST_STATE_RING: $ret['data'] = 'Line is ringing'; break;
case AST_STATE_RINGING: $ret['data'] = 'Remote end is ringing'; break;
case AST_STATE_UP: $ret['data'] = 'Line is up'; break;
case AST_STATE_BUSY: $ret['data'] = 'Line is busy'; break;
case AST_STATE_DIALING_OFFHOOK: $ret['data'] = 'Digits (or equivalent) have been dialed while offhook'; break;
case AST_STATE_PRERING: $ret['data'] = 'Channel has detected an incoming call and is waiting for ring'; break;
default: $ret['data'] = "Unknown ({$ret['result']})"; break;
}
return $ret;
}
/**
* Deletes an entry in the Asterisk database for a given family and key.
*
* @link http://www.voip-info.org/wiki-database+del
* @param string $family
* @param string $key
* @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise.
*/
function database_del($family, $key)
{
return $this->evaluate("DATABASE DEL \"$family\" \"$key\"");
}
/**
* Deletes a family or specific keytree within a family in the Asterisk database.
*
* @link http://www.voip-info.org/wiki-database+deltree
* @param string $family
* @param string $keytree
* @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise.
*/
function database_deltree($family, $keytree='')
{
$cmd = "DATABASE DELTREE \"$family\"";
if($keytree != '') $cmd .= " \"$keytree\"";
return $this->evaluate($cmd);
}
/**
* Retrieves an entry in the Asterisk database for a given family and key.
*
* @link http://www.voip-info.org/wiki-database+get
* @param string $family
* @param string $key
* @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 failure. ['data'] holds the value
*/
function database_get($family, $key)
{
return $this->evaluate("DATABASE GET \"$family\ \"$key\"");
}
/**
* Adds or updates an entry in the Asterisk database for a given family, key, and value.
*
* @param string $family
* @param string $key
* @param string $value
* @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise
*/
function database_put($family, $key, $value)
{
$value = str_replace("\n", '\n', addslashes($value));
return $this->evaluate("DATABASE PUT \"$family\" \"$key\" \"$value\"");
}
/**
* Executes the specified Asterisk application with given options.
*
* @link http://www.voip-info.org/wiki-exec
* @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands
* @param string $application
* @param mixed $options
* @return array, see evaluate for return information. ['result'] is whatever the application returns, or -2 on failure to find application
*/
function exec($application, $options)
{
if(is_array($options)) $options = join('|', $options);
return $this->evaluate("EXEC $application $options");
}
/**
* Plays the given file and receives DTMF data.
*
* This is similar to STREAM FILE, but this command can accept and return many DTMF digits,
* while STREAM FILE returns immediately after the first DTMF digit is detected.
*
* Asterisk looks for the file to play in /var/lib/asterisk/sounds by default.
*
* If the user doesn't press any keys when the message plays, there is $timeout milliseconds
* of silence then the command ends.
*
* The user has the opportunity to press a key at any time during the message or the
* post-message silence. If the user presses a key while the message is playing, the
* message stops playing. When the first key is pressed a timer starts counting for
* $timeout milliseconds. Every time the user presses another key the timer is restarted.
* The command ends when the counter goes to zero or the maximum number of digits is entered,
* whichever happens first.
*
* If you don't specify a time out then a default timeout of 2000 is used following a pressed
* digit. If no digits are pressed then 6 seconds of silence follow the message.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -