Documentation is available at phpagi_1.php
1 <?php
2 /**
3 * phpagi-asmanager.php : PHP Asterisk Manager functions
4 * Website: http://phpagi.sourceforge.net
5 *
6 * $Id: phpagi-asmanager.php,v 1.9 2005/03/14 18:29:38 masham Exp $
7 *
8 * Copyright (c) 2004, 2005 Matthew Asham <matthewa@bcwireless.net>, David Eder <david@eder.us>
9 * All Rights Reserved.
10 *
11 * This software is released under the terms of the GNU Lesser General Public License v2.1
12 * A copy of which is available from http://www.gnu.org/copyleft/lesser.html
13 *
14 * We would be happy to list your phpagi based application on the phpagi
15 * website. Drop me an Email if you'd like us to list your program.
16 *
17 * @package phpAGI
18 * @version 2.0
19 */
20
21
22 /**
23 * Written for PHP 4.3.4, should work with older PHP 4.x versions.
24 * Please submit bug reports, patches, etc to http://sourceforge.net/projects/phpagi/
25 * Gracias. :)
26 *
27 */
28
29 if(!class_exists('AGI'))
30 {
31 require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'phpagi.php');
32 }
33
34 /**
35 * Asterisk Manager class
36 *
37 * @link http://www.voip-info.org/wiki-Asterisk+config+manager.conf
38 * @link http://www.voip-info.org/wiki-Asterisk+manager+API
39 * @example examples/sip_show_peer.php Get information about a sip peer
40 * @package phpAGI
41 */
42 class AGI_1 extends AGI
43 {
44 /**
45 * Response structure
46 *
47 * array('code'=>$code, 'result'=>$result, 'data'=>$data)
48 *
49 * @var array
50 * @access public
51 */
52 var $response;
53
54 /**
55 * Constructor
56 *
57 * @param string $config is the name of the config file to parse
58 * @param array $optconfig is an array of configuration vars and vals, stuffed into $this->config['phpagi']
59 */
60 function AGI_1($config=false, $optconfig=false)
61 {
62 if(!$config) $config = NULL;
63 if(!$optconfig) $optconfig = array();
64 parent::AGI($config, $optconfig);
65 }
66
67 /**
68 * Evaluate an AGI command
69 *
70 * @access private
71 * @param string $command
72 * @return array ('code'=>$code, 'result'=>$result, 'data'=>$data)
73 */
74 function evalutate($command)
75 {
76 $this->response = parent::evalute($command);
77 return $this->response;
78 }
79
80 /**
81 * Execute an AGI command
82 *
83 * @access private
84 * @param string $str
85 * @return array ('code'=>$code, 'result'=>$result, 'data'=>$data)
86 */
87 function agi_exec($str)
88 {
89 return $this->evaluate($str);
90 }
91
92 /**
93 * Check for error in result structure
94 *
95 * @param array $retarr
96 * @return boolean true on error
97 */
98 function agi_is_error($retarr)
99 {
100 // Returns TRUE if the command returned an error.
101
102 if($retarr['code'] != AGIRES_OK)
103 {
104 $this->conlog("DEBUG: Bad command? Returned code is {$retarr['code']} result={$retarr['result']}");
105 return true;
106 }
107
108 if(!isset($retarr['result']))
109 {
110 $this->conlog("DEBUG: No 'result' value returned from asterisk! Eww!");
111 return true;
112 }
113
114 if($retarr['result'] == -1)
115 return true;
116
117 return false;
118 }
119
120 /**
121 * Read the result from Asterisk
122 *
123 * @return array
124 */
125 function agi_readresult()
126 {
127 return $this->response;
128 }
129
130 /**
131 * Sends $message to the Asterisk console via the 'verbose' message system.
132 *
133 * If the Asterisk verbosity level is $vbl or greater, send $str to the console.
134 *
135 * The Asterisk verbosity system works as follows. The Asterisk user gets to set the desired verbosity at startup time or later
136 * using the console 'set verbose' command. Messages are displayed on the console if their verbose level is less than or equal
137 * to desired verbosity set by the user. More important messages should have a low verbose level; less important messages
138 * should have a high verbose level.
139 *
140 * @link http://www.voip-info.org/wiki-verbose
141 * @param string $str
142 * @param integer $vbl from 1 to 4
143 */
144 function agi_verbose($str, $vbl=1)
145 {
146 $this->verbose($str, $vbl);
147 }
148
149 /**
150 * Get the response code from the last command
151 *
152 * @return integer
153 */
154 function agi_response_code()
155 {
156 return $this->response['code'];
157 }
158
159 /**
160 * Get the result code from the last command
161 *
162 * @return integer
163 */
164 function agi_response_result()
165 {
166 $this->conlog("result is {$this->response['result']}");
167 return $this->response['result'];
168 }
169
170 /**
171 * Get the response data from the last command
172 *
173 * @return string
174 */
175 function agi_response_data()
176 {
177 return $this->response['data'];
178 }
179
180 /**
181 * Get the response variable from the last command
182 *
183 * @param string $var
184 * @return mixed
185 */
186 function agi_response_var($var)
187 {
188 if(!isset($this->response[$var]))
189 return false;
190 return $this->response[$var];
191 }
192
193 /**
194 * Check for error in response
195 *
196 * @return boolean true on error
197 */
198 function agi_response_is_error()
199 {
200 return $this->agi_is_error($this->response);
201 }
202
203 /**
204 * Log to console if debug mode
205 *
206 * @param array $arr to print
207 * @param string $label
208 * @param integer $vbl verbose level
209 */
210 function con_print_r($arr, $label='', $lvl=0)
211 {
212 if($lvl == 0 && $label != '')
213 $this->conlog("debug: $label");
214
215 $this->conlog(print_r($arr, true), $lvl);
216 }
217
218
219 /**
220 * Plays the given file and receives DTMF data.
221 *
222 * This is similar to STREAM FILE, but this command can accept and return many DTMF digits,
223 * while STREAM FILE returns immediately after the first DTMF digit is detected.
224 *
225 * Asterisk looks for the file to play in /var/lib/asterisk/sounds by default.
226 *
227 * If the user doesn't press any keys when the message plays, there is $timeout milliseconds
228 * of silence then the command ends.
229 *
230 * The user has the opportunity to press a key at any time during the message or the
231 * post-message silence. If the user presses a key while the message is playing, the
232 * message stops playing. When the first key is pressed a timer starts counting for
233 * $timeout milliseconds. Every time the user presses another key the timer is restarted.
234 * The command ends when the counter goes to zero or the maximum number of digits is entered,
235 * whichever happens first.
236 *
237 * Pressing the # key has the same effect as the timer running out: the command ends and
238 * any previously keyed digits are returned. A side effect of this is that there is no
239 * way to read a # key using this command.
240 *
241 * @link http://www.voip-info.org/wiki-get+data
242 * @param integer $len number of digits to read
243 * @param integer $timeout milliseconds
244 * @param string $terminator character on which to quit
245 * @param string $prompt file to play. Do not include file extension.
246 * @return array of characters
247 */
248 function agi_getdtmf($len, $timeout, $terminator=false, $prompt=false)
249 {
250 if($prompt)
251 {
252 if(!is_array($prompt)) $prompt = array($prompt);
253
254 foreach($prompt as $p)
255 {
256 if($p[0] == '$')
257 {
258 $this->text2wav(substr($p, 1));
259 }
260 else
261 {
262 $this->stream_file($p, '#');
263 }
264 }
265 }
266
267 $ret = array();
268 for($i = 0; $i < $len; $i++)
269 {
270 $res = $this->wait_for_digit($timeout);
271 $this->con_print_r($res);
272 if($this->agi_response_is_error())
273 {
274 $this->conlog('error?');
275 return false;
276 }
277 $ch = chr($res['result']);
278 $this->conlog("got $ch");
279 if($terminator && $ch == $terminator)
280 return $ret;
281
282 $ret[$i] = $ch;
283 }
284 return($ret);
285 }
286
287 /**
288 * Read $len characters as DTMF codes
289 *
290 * @param integer $len
291 * @return string
292 */
293 function agi_dtmf2text($len)
294 {
295 $numbers=array('1'=>'1', '2'=>'2abc', '3'=>'3def', '4'=>'4ghi', '5'=>'5jkl', '6'=>'6mno',
296 '7'=>'7pqrs', '8'=>'8tuv', '9'=>'9wxyz', '0'=>'0');
297
298 $last = false;
299 $i = $times = 0;
300 $abort = 0;
301
302 $char = '';
303 do
304 {
305 $res = $this->agi_getdtmf(1, 4000);
306 $res = $res[0];
307
308 if($res == false) break;
309
310 if($last == false)
311 $last = $res;
312 elseif($last != $res || $res == false)
313 {
314 $ret[$i] = $char;
315 $this->conlog("Character $i is $char");
316 // $this->text2wav($char);
317 $times = 0;
318 $i++;
319 }
320
321 $char = $numbers[$res][$times++];
322 $this->conlog("Number $res is '$char'");
323
324 if(strlen($numbers[$res]) == $times) $times = 0;
325
326 $last = $res;
327 } while($i < $len && !$abort);
328
329 $str = '';
330 foreach($ret as $k) $str .= $k . ' ';
331
332 $this->text2wav($str);
333 return($str);
334 }
335
336 /**
337 * Alias of PHP join function
338 *
339 * @param array $arr
340 * @return string
341 */
342 function arr2str($arr)
343 {
344 return trim(join(' ', $arr));
345 }
346
347 /**
348 * Retrieves an entry in the Asterisk database for a given family and key.
349 *
350 * @link http://www.voip-info.org/wiki-database+get
351 * @param string $family
352 * @param string $key
353 * @return string
354 */
355 function db_get($family, $key)
356 {
357 $res = $this->database_get($family, $key);
358 if($res['code'] != AGIRES_OK || $res['result'] == 0) return false;
359 return $res['data'];
360 }
361
362 /**
363 * Adds or updates an entry in the Asterisk database for a given family, key, and value.
364 *
365 * @param string $family
366 * @param string $key
367 * @param string $val
368 * @return integer result code
369 */
370 function db_put($family, $key, $val)
371 {
372 $res = $this->database_put($family, $key, $val);
373 return $res['code'];
374 }
375
376 /**
377 * Deletes an entry in the Asterisk database for a given family and key.
378 *
379 * @link http://www.voip-info.org/wiki-database+del
380 * @param string $family
381 * @param string $key
382 * @return integer result code
383 */
384 function db_del($family, $key)
385 {
386 $res = $this->database_del($family, $key);
387 return $res['code'];
388 }
389
390 /**
391 * Fetch the value of a variable.
392 *
393 * Does not work with global variables. Does not work with some variables that are generated by modules.
394 *
395 * @link http://www.voip-info.org/wiki-get+variable
396 * @link http://www.voip-info.org/wiki-Asterisk+variables
397 * @param string $var variable name
398 * @return string
399 */
400 function get_var($var)
401 {
402 $res = $this->get_variable($var);
403 if($res['code'] != AGIRES_OK || $res['result'] == 0) return false;
404 return $res['data'];
405 }
406
407 /**
408 * Sets a variable to the specified value. The variables so created can later be used by later using ${<variablename>}
409 * in the dialplan.
410 *
411 * These variables live in the channel Asterisk creates when you pickup a phone and as such they are both local and temporary.
412 * Variables created in one channel can not be accessed by another channel. When you hang up the phone, the channel is deleted
413 * and any variables in that channel are deleted as well.
414 *
415 * @link http://www.voip-info.org/wiki-set+variable
416 * @param string $var is case sensitive
417 * @param string $val
418 * @return integer result code
419 */
420 function set_var($var, $val)
421 {
422 $res = $this->set_variable($var, $val);
423 return $res['code'];
424 }
425
426 /**
427 * Hangup the current channel.
428 *
429 * @link http://www.voip-info.org/wiki-hangup
430 * @param string $channel
431 */
432 function agi_hangup()
433 {
434 $this->hangup();
435 }
436
437 /**
438 * Get the status of the specified channel.
439 *
440 * @link http://www.voip-info.org/wiki-channel+status
441 * @param string $channel
442 * @return array, ('status'=>$res['result'], 'description'=>$res['data'])
443 */
444 function agi_channel_status($channel)
445 {
446 $res = $this->channel_status($channel);
447 return array('status'=>$res['result'], 'description'=>$res['data']);
448 }
449
450 /**
451 * Record sound to a file until an acceptable DTMF digit is received or a specified amount of
452 * time has passed. Optionally the file BEEP is played before recording begins.
453 *
454 * @link http://www.voip-info.org/wiki-record+file
455 * @param string $file to record, without extension, often created in /var/lib/asterisk/sounds
456 * @param string $format of the file. GSM and WAV are commonly used formats. MP3 is read-only and thus cannot be used.
457 * @param integer $timeout is the maximum record time in milliseconds, or -1 for no timeout.
458 * @param string $prompt to play
459 */
460 function agi_recordfile($file, $format, $timeout=5000, $prompt=FALSE)
461 {
462 if($prompt) $this->stream_file($prompt);
463 $this->record_file($file, $format, '#', $timeout, true);
464 }
465
466 /**
467 * Play the given audio file, allowing playback to be interrupted by a #. This command is similar to the GET DATA
468 * command but this command returns after the first DTMF digit has been pressed while GET DATA can accumulated any number of
469 * digits before returning.
470 *
471 * @link http://www.voip-info.org/wiki-stream+file
472 * @param string $file filename without extension, often in /var/lib/asterisk/sounds
473 */
474 function agi_play($file)
475 {
476 $this->stream_file($file, '#');
477 }
478
479 /**
480 * Goto - Set context, extension and priority
481 *
482 * @param string $con context
483 * @param string $ext extension
484 * @param string $pri priority
485 */
486 function agi_goto($con,$ext='s',$pri=1)
487 {
488 $this->goto($con, $ext, $pri);
489 }
490
491 /**
492 * Say the given digit string, returning early if # is received on the channel.
493 *
494 * @link http://www.voip-info.org/wiki-say+digits
495 * @param integer $digits
496 */
497 function agi_saydigits($digits)
498 {
499 $this->say_digits($digits, '#');
500 }
501
502 /**
503 * Say the given number, returning early if # is received on the channel.
504 *
505 * @link http://www.voip-info.org/wiki-say+number
506 * @param integer $number
507 */
508 function agi_saynumber($number)
509 {
510 $this->say_number($number, '#');
511 }
512
513 /**
514 * Say a given time, returning early if # is received on the channel.
515 *
516 * @link http://www.voip-info.org/wiki-say+time
517 * @param integer $time number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).
518 */
519 function agi_saytime($time='')
520 {
521 if($time == '') $time = time();
522 $this->say_time($time, '#');
523 }
524
525 /**
526 * Set Language
527 *
528 * @param string $language code
529 */
530 function agi_setlanguage($language='en')
531 {
532 $this->exec_setlanguage($language);
533 }
534
535 /**
536 * Perform enum lookup
537 *
538 * @param string $telnumber
539 * @param string $rDNS
540 * @return array
541 */
542 function enum_lookup($telnumber, $rDNS='e164.org')
543 {
544 // returns a sorted array of enum records
545
546 if($telnumber[0] == '+')
547 $telnumber = substr($telnumber, 1);
548
549 for($i = 0; $i < strlen($telnumber); $i++)
550 $rDNS = $telnumber[$i] . '.' . $rDNS;
551
552 if(!isset($this->config['phpagi']['dig'])) $this->config['phpagi']['dig'] = $this->which('dig');
553 $dig=trim($this->config['phpagi']['dig']);
554
555 $execstr= $dig . " +short " . escapeshellarg($rDNS) . " NAPTR";
556 $lines = trim(`$execstr`);
557
558 $lines = explode("\n", $lines);
559 $arr = array();
560 foreach($lines as $line)
561 {
562 $line = trim($line);
563 $line = str_replace("\t", ' ', $line);
564 while(strstr($line, ' '))
565 $line = str_replace(' ', ' ', $line);
566 $line = str_replace("\"", '', $line);
567 $line = str_replace("\'", '', $line);
568 $line = str_replace(' ', '|', $line);
569 $bits = explode('|', $line);
570 $bit = explode('!', stripslashes($bits[4]));
571 $URI = @ereg_replace($bit[1], $bit[2], '+' . $telnumber);
572 if($URI[3] == ':') $URI[3] = '/';
573 if($URI[4] == ':') $URI[4] = '/';
574 $arr[] = array('order'=>$bits[0], 'prio'=>$bits[1], 'tech'=>$bits[3], 'URI'=>$URI);
575 }
576
577 foreach($arr as $key=>$row)
578 {
579 $order[$key] = $row['order'];
580 $prio[$key] = $row['prio'];
581 }
582
583 array_multisort($order, SORT_ASC, $prio, SORT_ASC, $arr);
584 return($arr);
585 }
586
587 /**
588 * Perform enum txt lookup
589 *
590 * @param string $telnumber
591 * @param string $rDNS
592 * @return string
593 */
594 function enum_txtlookup($telnumber, $rDNS='e164.org')
595 {
596 // returns the contents of a TXT record associated with an ENUM dns record.
597 // ala reverse caller ID lookup.
598 if($telnumber[0] == '+')
599 $telnumber = substr($telnumber, 1);
600
601 for($i = 0; $i < strlen($telnumber); $i++)
602 $rDNS = $telnumber[$i] . '.' . $rDNS;
603
604 if(!isset($this->config['phpagi']['dig'])) $this->config['phpagi']['dig'] = $this->which('dig');
605 $dig=trim($this->config['phpagi']['dig']);
606
607 $execstr = $dig . ' +short ' . escapeshellarg($rDNS) . ' TXT';
608 $lines = trim(`$execstr`);
609
610 $lines = explode("\n", $lines);
611 foreach($lines as $line)
612 {
613 $line = str_replace("\t", ' ', trim($line));
614 while(strstr($line, ' ')) $line = str_replace(' ', ' ', $line);
615 $line = str_replace("\"", '', $line);
616 $line = str_replace("\'", '', $line);
617 $ret .= $line;
618 }
619 $ret = trim($ret);
620 if($ret == '') return false;
621 return $ret;
622 }
623
624 /**
625 * Send the given text to the connected channel.
626 *
627 * Most channels do not support transmission of text.
628 *
629 * @link http://www.voip-info.org/wiki-send+text
630 * @param $text
631 * @return boolean true on success
632 */
633 function send_text($txt)
634 {
635 $res = parent::send_text($txt);
636 if($res['code'] != AGIRES_OK || $res['result'] == -1) return false;
637 return true;
638 }
639
640 /**
641 * Send the specified image on a channel.
642 *
643 * Most channels do not support the transmission of images.
644 *
645 * @link http://www.voip-info.org/wiki-send+image
646 * @param string $image without extension, often in /var/lib/asterisk/images
647 * @return boolean true on success
648 */
649 function send_image($image)
650 {
651 $res = parent::send_image($image);
652 if($res['code'] != AGIRES_OK || $res['result'] == -1) return false;
653 return true;
654 }
655 }
656 ?>
Documentation generated on Wed, 25 May 2005 14:30:04 -0600 by phpDocumentor 1.2.3