Passed
Push — master ( af4cfe...ae3250 )
by Chizhov
01:31
created

AGI_AsteriskManager::__construct()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 8
c 1
b 0
f 0
nc 12
nop 2
dl 0
loc 16
rs 9.2222
1
<?php
2
/**
3
 * phpagi-asmanager.php : PHP Asterisk Manager functions
4
 * @see https://github.com/welltime/phpagi
5
 * @filesource http://phpagi.sourceforge.net/
6
 *
7
 * $Id: phpagi-asmanager.php,v 1.10 2005/05/25 18:43:48 pinhole Exp $
8
 *
9
 * Copyright (c) 2004 - 2010 Matthew Asham <[email protected]>, David Eder <[email protected]> and others
10
 * All Rights Reserved.
11
 *
12
 * This software is released under the terms of the GNU Lesser General Public License v2.1
13
 *  A copy of which is available from http://www.gnu.org/copyleft/lesser.html
14
 *
15
 * We would be happy to list your phpagi based application on the phpagi
16
 * website.  Drop me an Email if you'd like us to list your program.
17
 *
18
 * @package phpAGI
19
 * @version 2.0
20
 */
21
22
23
/**
24
 * Written for PHP 4.3.4, should work with older PHP 4.x versions.
25
 * Please submit bug reports, patches, etc to https://github.com/welltime/phpagi
26
 *
27
 */
28
29
if (!class_exists('AGI')) {
30
  require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'phpagi.php');
31
}
32
33
/**
34
 * Asterisk Manager class
35
 *
36
 * @link http://www.voip-info.org/wiki-Asterisk+config+manager.conf
37
 * @link http://www.voip-info.org/wiki-Asterisk+manager+API
38
 * @example examples/sip_show_peer.php Get information about a sip peer
39
 * @package phpAGI
40
 */
41
class AGI_AsteriskManager
42
{
43
  /**
44
   * Config variables
45
   *
46
   * @var array
47
   * @access public
48
   */
49
  public $config;
50
51
  /**
52
   * Socket
53
   *
54
   * @access public
55
   */
56
  public $socket = null;
57
58
  /**
59
   * Server we are connected to
60
   *
61
   * @access public
62
   * @var string
63
   */
64
  public $server;
65
66
  /**
67
   * Port on the server we are connected to
68
   *
69
   * @access public
70
   * @var integer
71
   */
72
  public $port;
73
74
  /**
75
   * Parent AGI
76
   *
77
   * @access private
78
   * @var AGI
79
   */
80
  private $pagi = false;
81
82
  /**
83
   * Event Handlers
84
   *
85
   * @access private
86
   * @var array
87
   */
88
  private $event_handlers;
89
90
  private $_buffer = null;
91
92
  /**
93
   * Whether we're successfully logged in
94
   *
95
   * @access private
96
   * @var boolean
97
   */
98
  private $_logged_in = false;
99
100
  private $defaultConfig = ["server" => 'localhost',
101
                            "port" => 5038,
102
                            "username" => "phpagi",
103
                            "secret" => "phpagi",
104
                            "write_log" => false];
105
106
  public function setPagi(&$agi) {
107
    $this->pagi = $agi;
108
  }
109
110
  /**
111
   * Constructor
112
   *
113
   * @param string $config is the name of the config file to parse or a parent agi from which to read the config
114
   * @param array $optconfig is an array of configuration vars and values, stuffed into $this->config['asmanager']
115
   */
116
  function __construct($config = null, array $optconfig = []) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
117
    // load config
118
    if (!is_null($config) && file_exists($config)) {
119
      $this->config = parse_ini_file($config, true);
120
    } elseif (file_exists(DEFAULT_PHPAGI_CONFIG)) {
121
      $this->config = parse_ini_file(DEFAULT_PHPAGI_CONFIG, true);
122
    }
123
124
    // If optconfig is specified, stuff values and vars into 'asmanager' config array.
125
    foreach ($optconfig as $var => $val) {
126
      $this->config['asmanager'][$var] = $val;
127
    }
128
129
    // add default values to config for uninitialized values
130
    foreach (array_keys($this->defaultConfig) as $name => $value) {
131
      $this->config['asmanager'][$name] = $this->config['asmanager'][$name] ?? $value;
132
    }
133
  }
134
135
  /**
136
   * Send a request
137
   *
138
   * @param string $action
139
   * @param array $parameters
140
   * @return array of parameters
141
   * @throws Exception
142
   */
143
  function send_request(string $action, array $parameters = []): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
144
    $req = "Action: $action\r\n";
145
    $actionid = null;
146
    foreach ($parameters as $var => $val) {
147
      if (is_array($val)) {
148
        foreach ($val as $line) {
149
          $req .= "$var: $line\r\n";
150
        }
151
        continue;
152
      }
153
      $req .= "$var: $val\r\n";
154
      if (strtolower($var) == "actionid") {
155
        $actionid = $val;
156
      }
157
    }
158
    if (!$actionid) {
159
      $actionid = $this->ActionID();
160
      $req .= "ActionID: $actionid\r\n";
161
    }
162
    $req .= "\r\n";
163
164
    fwrite($this->socket, $req);
165
166
    return $this->wait_response(false, $actionid);
167
  }
168
169
  /**
170
   * @param bool $allow_timeout
171
   * @return array
172
   * @throws Exception
173
   */
174
  function read_one_msg(bool $allow_timeout = false): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Unused Code introduced by
The parameter $allow_timeout is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

174
  function read_one_msg(/** @scrutinizer ignore-unused */ bool $allow_timeout = false): array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
175
    $type = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $type is dead and can be removed.
Loading history...
176
177
    do {
178
      $buf = fgets($this->socket, 4096);
179
      if (false === $buf) {
180
        throw new Exception("Error reading from AMI socket");
181
      }
182
      $this->_buffer .= $buf;
183
184
      $pos = strpos($this->_buffer, "\r\n\r\n");
185
      if (false !== $pos) {
186
        // there's a full message in the buffer
187
        break;
188
      }
189
    } while (!feof($this->socket));
190
191
    $msg = substr($this->_buffer, 0, $pos);
192
    $this->_buffer = substr($this->_buffer, $pos + 4);
193
194
    $msgarr = explode("\r\n", $msg);
195
196
    $parameters = [];
197
198
    $r = explode(': ', $msgarr[0]);
199
    $type = strtolower($r[0]);
200
201
    if (in_array($r[1], ['Success', 'Follows'])) {
202
      $str = array_pop($msgarr);
203
      $lastline = strpos($str, '--END COMMAND--');
204
      if (false !== $lastline) {
205
        $parameters['data'] = substr($str, 0, $lastline - 1); // cut '\n' too
206
      }
207
    }
208
209
    $haveData = array_key_exists("data", $parameters);
210
    $asteriskRawOutput = [];
211
212
    foreach ($msgarr as $num => $str) {
213
      $kv = explode(':', $str, 2);
214
      if (!isset($kv[1])) {
215
        $kv[1] = "";
216
      }
217
      $key = trim($kv[0]);
218
      $val = trim($kv[1]);
219
      if (!$haveData && mb_strtolower($key) == "output") {
220
        $asteriskRawOutput[] = $val;
221
        continue;
222
      }
223
      $parameters[$key] = $val;
224
    }
225
    if (!$haveData && count($asteriskRawOutput)) {
226
      $parameters["data"] = implode("\n", $asteriskRawOutput);
227
    }
228
229
    // process response
230
    switch ($type) {
231
      case '': // timeout occurred
232
        // $timeout = $allow_timeout;
233
        break;
234
      case 'event':
235
        $this->process_event($parameters);
236
        break;
237
      case 'response':
238
        break;
239
      default:
240
        $this->log('Unhandled response packet from Manager: ' . print_r($parameters, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($parameters, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

240
        $this->log('Unhandled response packet from Manager: ' . /** @scrutinizer ignore-type */ print_r($parameters, true));
Loading history...
241
        break;
242
    }
243
244
    return $parameters;
245
  }
246
247
  /**
248
   * Wait for a response
249
   *
250
   * If a request was just sent, this will return the response.
251
   * Otherwise, it will loop forever, handling events.
252
   *
253
   * XXX this code is slightly better then the original one
254
   * however it's still totally screwed up and needs to be rewritten,
255
   * for two reasons at least:
256
   * 1. it does not handle socket errors in any way
257
   * 2. it is terribly synchronous, esp. with eventlists,
258
   *    i.e. your code is blocked on waiting until full response is received
259
   *
260
   * @param boolean $allow_timeout if the socket times out, return an empty array
261
   * @param string $actionid
262
   * @return array of parameters, empty on timeout
263
   * @throws Exception
264
   */
265
  function wait_response(bool $allow_timeout = false, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
266
    if ($actionid) {
267
      do {
268
        $res = $this->read_one_msg($allow_timeout);
269
      } while (!(isset($res['ActionID']) && $res['ActionID'] == $actionid));
270
    } else {
271
      $res = $this->read_one_msg($allow_timeout);
272
      return $res;
273
    }
274
275
    if (isset($res['EventList']) && $res['EventList'] == 'start') {
276
      $evlist = [];
277
      do {
278
        $res = $this->wait_response(false, $actionid);
279
        if (isset($res['EventList']) && $res['EventList'] == 'Complete') {
280
          break;
281
        }
282
        $evlist[] = $res;
283
      } while (true);
284
      $res['events'] = $evlist;
285
    }
286
287
    return $res;
288
  }
289
290
291
  /**
292
   * Connect to Asterisk
293
   *
294
   * @param string $server
295
   * @param string $username
296
   * @param string $secret
297
   * @return boolean true on success
298
   * @throws Exception
299
   * @example examples/sip_show_peer.php Get information about a sip peer
300
   *
301
   */
302
  function connect($server = null, $username = null, $secret = null): bool {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
303
    // use config if not specified
304
    if (is_null($server)) {
305
      $server = $this->config['asmanager']['server'];
306
    }
307
    if (is_null($username)) {
308
      $username = $this->config['asmanager']['username'];
309
    }
310
    if (is_null($secret)) {
311
      $secret = $this->config['asmanager']['secret'];
312
    }
313
314
    // get port from server if specified
315
    if (strpos($server, ':') !== false) {
316
      $c = explode(':', $server);
317
      $this->server = $c[0];
318
      $this->port = $c[1];
0 ignored issues
show
Documentation Bug introduced by
The property $port was declared of type integer, but $c[1] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
319
    } else {
320
      $this->server = $server;
321
      $this->port = $this->config['asmanager']['port'];
322
    }
323
324
    // connect the socket
325
    $errno = $errstr = null;
326
    $this->socket = fsockopen($this->server, $this->port, $errno, $errstr);
327
    if ($this->socket === false) {
328
      $this->log("Unable to connect to manager {$this->server}:{$this->port} ($errno): $errstr");
329
      return false;
330
    }
331
332
    // read the header
333
    $str = fgets($this->socket);
334
    if ($str === false) {
335
      // a problem.
336
      $this->log("Asterisk Manager header not received.");
337
      return false;
338
    }
339
340
    // login
341
    $res = $this->send_request('login', ['Username' => $username,
342
                                         'Secret' => $secret]);
343
    if ($res['Response'] != 'Success') {
344
      $this->_logged_in = false;
345
      $this->log("Failed to login.");
346
      $this->disconnect();
347
      return false;
348
    }
349
    $this->_logged_in = true;
350
    return true;
351
  }
352
353
  /**
354
   * Disconnect
355
   *
356
   * @throws Exception
357
   * @example examples/sip_show_peer.php Get information about a sip peer
358
   */
359
  function disconnect() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
360
    if ($this->_logged_in) {
361
      $this->logoff();
362
    }
363
    fclose($this->socket);
364
  }
365
366
  // *********************************************************************************************************
367
  // **                       COMMANDS                                                                      **
368
  // *********************************************************************************************************
369
370
  /**
371
   * Set Absolute Timeout
372
   *
373
   * Hangup a channel after a certain time.
374
   *
375
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+AbsoluteTimeout
376
   * @param string $channel Channel name to hangup
377
   * @param integer $timeout Maximum duration of the call (sec)
378
   * @return array
379
   * @throws Exception
380
   */
381
  function AbsoluteTimeout(string $channel, int $timeout): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
382
    return $this->send_request('AbsoluteTimeout', ['Channel' => $channel,
383
                                                   'Timeout' => $timeout]);
384
  }
385
386
  /**
387
   * Change monitoring filename of a channel
388
   *
389
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ChangeMonitor
390
   * @param string $channel the channel to record.
391
   * @param string $file the new name of the file created in the monitor spool directory.
392
   * @return array
393
   * @throws Exception
394
   */
395
  function ChangeMonitor(string $channel, string $file): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
396
    return $this->send_request('ChangeMonitor', ['Channel' => $channel,
397
                                                 'File' => $file]);
398
  }
399
400
  /**
401
   * Execute Command
402
   *
403
   * @param string $command
404
   * @param string $actionid message matching variable
405
   * @return array
406
   * @throws Exception
407
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Command
408
   * @link http://www.voip-info.org/wiki-Asterisk+CLI
409
   * @example examples/sip_show_peer.php Get information about a sip peer
410
   */
411
  function Command(string $command, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
412
    $parameters = ['Command' => $command];
413
    if ($actionid) {
414
      $parameters['ActionID'] = $actionid;
415
    }
416
    return $this->send_request('Command', $parameters);
417
  }
418
419
  /**
420
   * Enable/Disable sending of events to this manager
421
   *
422
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Events
423
   * @param string $eventmask is either 'on', 'off', or 'system,call,log'
424
   * @return array
425
   * @throws Exception
426
   */
427
  function Events(string $eventmask): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
428
    return $this->send_request('Events', ['EventMask' => $eventmask]);
429
  }
430
431
  /**
432
   *  Generate random ActionID
433
   **/
434
  function ActionID(): string {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
435
    return "A" . sprintf(rand(), "%6d");
436
  }
437
438
  /**
439
   *
440
   *  DBGet
441
   *  http://www.voip-info.org/wiki/index.php?page=Asterisk+Manager+API+Action+DBGet
442
   * @param string $family key family
443
   * @param string $key key name
444
   * @param string $actionid
445
   * @return string
446
   *
447
   * @throws Exception
448
   */
449
  function DBGet(string $family, string $key, $actionid = null): string {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
450
    $parameters = ['Family' => $family,
451
                   'Key' => $key];
452
    if ($actionid == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $actionid of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
453
      $actionid = $this->ActionID();
454
    }
455
    $parameters['ActionID'] = $actionid;
456
    $response = $this->send_request("DBGet", $parameters);
457
    if ($response['Response'] == "Success") {
458
      $response = $this->wait_response(false, $actionid);
459
      return $response['Val'];
460
    }
461
    return "";
462
  }
463
464
  /**
465
   * Check Extension Status
466
   *
467
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ExtensionState
468
   * @param string $exten Extension to check state on
469
   * @param string $context Context for extension
470
   * @param string $actionid message matching variable
471
   * @return array
472
   * @throws Exception
473
   */
474
  function ExtensionState(string $exten, string $context, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
475
    $parameters = ['Exten' => $exten,
476
                   'Context' => $context];
477
    if ($actionid) {
478
      $parameters['ActionID'] = $actionid;
479
    }
480
    return $this->send_request('ExtensionState', $parameters);
481
  }
482
483
  /**
484
   * Gets a Channel Variable
485
   *
486
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+GetVar
487
   * @link http://www.voip-info.org/wiki-Asterisk+variables
488
   * @param string $channel Channel to read variable from
489
   * @param string $variable
490
   * @param string $actionid message matching variable
491
   * @return array
492
   * @throws Exception
493
   */
494
  function GetVar(string $channel, string $variable, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
495
    $parameters = ['Channel' => $channel,
496
                   'Variable' => $variable];
497
    if ($actionid) {
498
      $parameters['ActionID'] = $actionid;
499
    }
500
    return $this->send_request('GetVar', $parameters);
501
  }
502
503
  /**
504
   * Hangup Channel
505
   *
506
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Hangup
507
   * @param string $channel The channel name to be hangup
508
   * @return array
509
   * @throws Exception
510
   */
511
  function Hangup(string $channel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
512
    return $this->send_request('Hangup', ['Channel' => $channel]);
513
  }
514
515
  /**
516
   * List IAX Peers
517
   *
518
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+IAXpeers
519
   * @throws Exception
520
   */
521
  function IAXPeers(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
522
    return $this->send_request('IAXPeers');
523
  }
524
525
  /**
526
   * List available manager commands
527
   *
528
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ListCommands
529
   * @param string $actionid message matching variable
530
   * @return array
531
   * @throws Exception
532
   */
533
  function ListCommands($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
534
    return $this->send_request('ListCommands', $actionid ? ['ActionID' => $actionid] : []);
535
  }
536
537
  /**
538
   * Logoff Manager
539
   *
540
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Logoff
541
   * @throws Exception
542
   */
543
  function Logoff(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
544
    return $this->send_request('Logoff');
545
  }
546
547
  /**
548
   * Check Mailbox Message Count
549
   *
550
   * Returns number of new and old messages.
551
   *   Message: Mailbox Message Count
552
   *   Mailbox: <mailboxid>
553
   *   NewMessages: <count>
554
   *   OldMessages: <count>
555
   *
556
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+MailboxCount
557
   * @param string $mailbox Full mailbox ID <mailbox>@<vm-context>
558
   * @param string $actionid message matching variable
559
   * @return array
560
   * @throws Exception
561
   */
562
  function MailboxCount(string $mailbox, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
563
    $parameters = ['Mailbox' => $mailbox];
564
    if ($actionid) {
565
      $parameters['ActionID'] = $actionid;
566
    }
567
    return $this->send_request('MailboxCount', $parameters);
568
  }
569
570
  /**
571
   * Check Mailbox
572
   *
573
   * Returns number of messages.
574
   *   Message: Mailbox Status
575
   *   Mailbox: <mailboxid>
576
   *   Waiting: <count>
577
   *
578
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+MailboxStatus
579
   * @param string $mailbox Full mailbox ID <mailbox>@<vm-context>
580
   * @param string $actionid message matching variable
581
   * @return array
582
   * @throws Exception
583
   */
584
  function MailboxStatus(string $mailbox, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
585
    $parameters = ['Mailbox' => $mailbox];
586
    if ($actionid) {
587
      $parameters['ActionID'] = $actionid;
588
    }
589
    return $this->send_request('MailboxStatus', $parameters);
590
  }
591
592
  /**
593
   * Monitor a channel
594
   *
595
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Monitor
596
   * @param string $channel
597
   * @param string $file
598
   * @param string $format
599
   * @param boolean $mix
600
   * @return array
601
   * @throws Exception
602
   */
603
  function Monitor(string $channel, $file = null, $format = null, $mix = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
604
    $parameters = ['Channel' => $channel];
605
    if ($file) {
606
      $parameters['File'] = $file;
607
    }
608
    if ($format) {
609
      $parameters['Format'] = $format;
610
    }
611
    if (!is_null($file)) {
612
      $parameters['Mix'] = ($mix) ? 'true' : 'false';
613
    }
614
    return $this->send_request('Monitor', $parameters);
615
  }
616
617
  /**
618
   * Originate Call
619
   *
620
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Originate
621
   * @param string $channel Channel name to call
622
   * @param string $exten Extension to use (requires 'Context' and 'Priority')
623
   * @param string $context Context to use (requires 'Exten' and 'Priority')
624
   * @param string $priority Priority to use (requires 'Exten' and 'Context')
625
   * @param string $application Application to use
626
   * @param string $data Data to use (requires 'Application')
627
   * @param integer $timeout How long to wait for call to be answered (in ms)
628
   * @param string $callerid Caller ID to be set on the outgoing channel
629
   * @param string $variable Channel variable to set (VAR1=value1|VAR2=value2)
630
   * @param string $account Account code
631
   * @param boolean $async true fast origination
632
   * @param string $actionid message matching variable
633
   * @return array
634
   * @throws Exception
635
   */
636
  function Originate(string $channel,
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
637
                     $exten = null, $context = null, $priority = null,
638
                     $application = null, $data = null,
639
                     $timeout = null, $callerid = null, $variable = null, $account = null, $async = null, $actionid = null): array {
640
    $parameters = ['Channel' => $channel];
641
642
    if ($exten) {
643
      $parameters['Exten'] = $exten;
644
    }
645
    if ($context) {
646
      $parameters['Context'] = $context;
647
    }
648
    if ($priority) {
649
      $parameters['Priority'] = $priority;
650
    }
651
652
    if ($application) {
653
      $parameters['Application'] = $application;
654
    }
655
    if ($data) {
656
      $parameters['Data'] = $data;
657
    }
658
659
    if ($timeout) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $timeout of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
660
      $parameters['Timeout'] = $timeout;
661
    }
662
    if ($callerid) {
663
      $parameters['CallerID'] = $callerid;
664
    }
665
    if ($variable) {
666
      $parameters['Variable'] = $variable;
667
    }
668
    if ($account) {
669
      $parameters['Account'] = $account;
670
    }
671
    if (!is_null($async)) {
672
      $parameters['Async'] = ($async) ? 'true' : 'false';
673
    }
674
    if ($actionid) {
675
      $parameters['ActionID'] = $actionid;
676
    }
677
678
    return $this->send_request('Originate', $parameters);
679
  }
680
681
  /**
682
   * List parked calls
683
   *
684
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ParkedCalls
685
   * @param string $actionid message matching variable
686
   * @return array
687
   * @throws Exception
688
   */
689
  function ParkedCalls($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
690
    return $this->send_request('ParkedCalls', $actionid ? ['ActionID' => $actionid] : []);
691
  }
692
693
  /**
694
   * Ping
695
   *
696
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Ping
697
   * @throws Exception
698
   */
699
  function Ping(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
700
    return $this->send_request('Ping');
701
  }
702
703
  /**
704
   * Queue Add
705
   *
706
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueAdd
707
   * @param string $queue
708
   * @param string $interface
709
   * @param integer $penalty
710
   * @param string $memberName
711
   * @return array
712
   * @throws Exception
713
   */
714
  function QueueAdd(string $queue, string $interface, int $penalty = 0, $memberName = false): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
715
    $parameters = ['Queue' => $queue,
716
                   'Interface' => $interface];
717
    if ($penalty) {
718
      $parameters['Penalty'] = $penalty;
719
    }
720
    if ($memberName) {
721
      $parameters["MemberName"] = $memberName;
722
    }
723
    return $this->send_request('QueueAdd', $parameters);
724
  }
725
726
  /**
727
   * Queue Remove
728
   *
729
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueRemove
730
   * @param string $queue
731
   * @param string $interface
732
   * @return array
733
   * @throws Exception
734
   */
735
  function QueueRemove(string $queue, string $interface): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
736
    return $this->send_request('QueueRemove', ['Queue' => $queue,
737
                                               'Interface' => $interface]);
738
  }
739
740
  /**
741
   * @return array
742
   * @throws Exception
743
   */
744
  function QueueReload(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
745
    return $this->send_request('QueueReload');
746
  }
747
748
  /**
749
   * Queues
750
   *
751
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Queues
752
   * @throws Exception
753
   */
754
  function Queues(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
755
    return $this->send_request('Queues');
756
  }
757
758
  /**
759
   * Queue Status
760
   *
761
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueStatus
762
   * @param string $actionid message matching variable
763
   * @return array
764
   * @throws Exception
765
   */
766
  function QueueStatus($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
767
    return $this->send_request('QueueStatus', $actionid ? ['ActionID' => $actionid] : []);
768
  }
769
770
  /**
771
   * Redirect
772
   *
773
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Redirect
774
   * @param string $channel
775
   * @param string $extrachannel
776
   * @param string $exten
777
   * @param string $context
778
   * @param string $priority
779
   * @return array
780
   * @throws Exception
781
   */
782
  function Redirect(string $channel, string $extrachannel, string $exten, string $context, string $priority): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
783
    return $this->send_request('Redirect', ['Channel' => $channel,
784
                                            'ExtraChannel' => $extrachannel,
785
                                            'Exten' => $exten,
786
                                            'Context' => $context,
787
                                            'Priority' => $priority]);
788
  }
789
790
  /**
791
   * @param string $channel
792
   * @param string $exten
793
   * @param string $context
794
   * @param string $priority
795
   * @return array
796
   * @throws Exception
797
   */
798
  function Atxfer(string $channel, string $exten, string $context, string $priority): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
799
    return $this->send_request('Atxfer', ['Channel' => $channel,
800
                                          'Exten' => $exten,
801
                                          'Context' => $context,
802
                                          'Priority' => $priority]);
803
  }
804
805
  /**
806
   * Set the CDR UserField
807
   *
808
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+SetCDRUserField
809
   * @param string $userfield
810
   * @param string $channel
811
   * @param string $append
812
   * @return array
813
   * @throws Exception
814
   */
815
  function SetCDRUserField(string $userfield, string $channel, $append = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
816
    $parameters = ['UserField' => $userfield,
817
                   'Channel' => $channel];
818
    if ($append) {
819
      $parameters['Append'] = $append;
820
    }
821
    return $this->send_request('SetCDRUserField', $parameters);
822
  }
823
824
  /**
825
   * Set Channel Variable
826
   *
827
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+SetVar
828
   * @param string $channel Channel to set variable for
829
   * @param string $variable name
830
   * @param string $value
831
   * @return array
832
   * @throws Exception
833
   */
834
  function SetVar(string $channel, string $variable, string $value): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
835
    return $this->send_request('SetVar', ['Channel' => $channel,
836
                                          'Variable' => $variable,
837
                                          'Value' => $value]);
838
  }
839
840
  /**
841
   * Channel Status
842
   *
843
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Status
844
   * @param string $channel
845
   * @param string $actionid message matching variable
846
   * @return array
847
   * @throws Exception
848
   */
849
  function Status(string $channel, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
850
    $parameters = ['Channel' => $channel];
851
    if ($actionid) {
852
      $parameters['ActionID'] = $actionid;
853
    }
854
    return $this->send_request('Status', $parameters);
855
  }
856
857
  /**
858
   * Stop monitoring a channel
859
   *
860
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+StopMonitor
861
   * @param string $channel
862
   * @return array
863
   * @throws Exception
864
   */
865
  function StopMonitor(string $channel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
866
    return $this->send_request('StopMonitor', ['Channel' => $channel]);
867
  }
868
869
  /**
870
   * Dial over Zap channel while offhook
871
   *
872
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDialOffhook
873
   * @param string $zapchannel
874
   * @param string $number
875
   * @return array
876
   * @throws Exception
877
   */
878
  function ZapDialOffhook(string $zapchannel, string $number): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
879
    return $this->send_request('ZapDialOffhook', ['ZapChannel' => $zapchannel,
880
                                                  'Number' => $number]);
881
  }
882
883
  /**
884
   * Toggle Zap channel Do Not Disturb status OFF
885
   *
886
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDNDoff
887
   * @param string $zapchannel
888
   * @return array
889
   * @throws Exception
890
   */
891
  function ZapDNDoff(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
892
    return $this->send_request('ZapDNDoff', ['ZapChannel' => $zapchannel]);
893
  }
894
895
  /**
896
   * Toggle Zap channel Do Not Disturb status ON
897
   *
898
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDNDon
899
   * @param string $zapchannel
900
   * @return array
901
   * @throws Exception
902
   */
903
  function ZapDNDon(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
904
    return $this->send_request('ZapDNDon', ['ZapChannel' => $zapchannel]);
905
  }
906
907
  /**
908
   * Hangup Zap Channel
909
   *
910
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapHangup
911
   * @param string $zapchannel
912
   * @return array
913
   * @throws Exception
914
   */
915
  function ZapHangup(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
916
    return $this->send_request('ZapHangup', ['ZapChannel' => $zapchannel]);
917
  }
918
919
  /**
920
   * Transfer Zap Channel
921
   *
922
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapTransfer
923
   * @param string $zapchannel
924
   * @return array
925
   * @throws Exception
926
   */
927
  function ZapTransfer(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
928
    return $this->send_request('ZapTransfer', ['ZapChannel' => $zapchannel]);
929
  }
930
931
  /**
932
   * Zap Show Channels
933
   *
934
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapShowChannels
935
   * @param string $actionid message matching variable
936
   * @return array
937
   * @throws Exception
938
   */
939
  function ZapShowChannels($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
940
    return $this->send_request('ZapShowChannels', $actionid ? ['ActionID' => $actionid] : []);
941
  }
942
943
  // *********************************************************************************************************
944
  // **                       MISC                                                                          **
945
  // *********************************************************************************************************
946
947
  /*
948
   * Log a message
949
   *
950
   * @param string $message
951
   * @param integer $level from 1 to 4
952
   */
953
  function log(string $message, int $level = 1) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
954
    if ($this->pagi != false) {
0 ignored issues
show
introduced by
The condition $this->pagi != false is always true.
Loading history...
955
      $this->pagi->conlog($message, $level);
956
    } elseif ($this->config['asmanager']['write_log']) {
957
      error_log(date('r') . ' - ' . $message);
958
    }
959
  }
960
961
  /**
962
   * Add event handler
963
   *
964
   * Known Events include ( http://www.voip-info.org/wiki-asterisk+manager+events )
965
   *   Link - Fired when two voice channels are linked together and voice data exchange commences.
966
   *   Unlink - Fired when a link between two voice channels is discontinued, for example, just before call completion.
967
   *   Newexten -
968
   *   Hangup -
969
   *   Newchannel -
970
   *   Newstate -
971
   *   Reload - Fired when the "RELOAD" console command is executed.
972
   *   Shutdown -
973
   *   ExtensionStatus -
974
   *   Rename -
975
   *   Newcallerid -
976
   *   Alarm -
977
   *   AlarmClear -
978
   *   Agentcallbacklogoff -
979
   *   Agentcallbacklogin -
980
   *   Agentlogoff -
981
   *   MeetmeJoin -
982
   *   MessageWaiting -
983
   *   join -
984
   *   leave -
985
   *   AgentCalled -
986
   *   ParkedCall - Fired after ParkedCalls
987
   *   Cdr -
988
   *   ParkedCallsComplete -
989
   *   QueueParams -
990
   *   QueueMember -
991
   *   QueueStatusEnd -
992
   *   Status -
993
   *   StatusComplete -
994
   *   ZapShowChannels - Fired after ZapShowChannels
995
   *   ZapShowChannelsComplete -
996
   *
997
   * @param string $event type or * for default handler
998
   * @param string $callback function
999
   * @return boolean success
1000
   */
1001
  function add_event_handler(string $event, string $callback): bool {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1002
    $event = strtolower($event);
1003
    if (isset($this->event_handlers[$event])) {
1004
      $this->log("$event handler is already defined, not over-writing.");
1005
      return false;
1006
    }
1007
    $this->event_handlers[$event] = $callback;
1008
    return true;
1009
  }
1010
1011
  /**
1012
   *
1013
   *   Remove event handler
1014
   *
1015
   * @param string $event type or * for default handler
1016
   * @return boolean success
1017
   **/
1018
  function remove_event_handler(string $event): bool {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1019
    $event = strtolower($event);
1020
    if (isset($this->event_handlers[$event])) {
1021
      unset($this->event_handlers[$event]);
1022
      return true;
1023
    }
1024
    $this->log("$event handler is not defined.");
1025
    return false;
1026
  }
1027
1028
  /**
1029
   * Process event
1030
   *
1031
   * @access private
1032
   * @param array $parameters
1033
   * @return mixed result of event handler or false if no handler was found
1034
   */
1035
  private function process_event(array $parameters) {
1036
    $ret = false;
1037
    $e = strtolower($parameters['Event']);
1038
    $this->log("Got event.. $e");
1039
1040
    $handler = '';
1041
    if (isset($this->event_handlers[$e])) {
1042
      $handler = $this->event_handlers[$e];
1043
    } elseif (isset($this->event_handlers['*'])) {
1044
      $handler = $this->event_handlers['*'];
1045
    }
1046
1047
    if (function_exists($handler)) {
1048
      $this->log("Execute handler $handler");
1049
      $ret = $handler($e, $parameters, $this->server, $this->port);
1050
    } elseif (is_array($handler)) {
1051
      $ret = call_user_func($handler, $e, $parameters, $this->server, $this->port);
1052
    } else {
1053
      $this->log("No event handler for event '$e'");
1054
    }
1055
    return $ret;
1056
  }
1057
}
1058