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