Howto:SOAP API PHP5 Sample Code

From innovaphone wiki
Jump to navigation Jump to search

Applies To

This information applies to

  • V9 and later innovaphone PBX platform
  • web server running PHP 5

innovaphone PBX web services can be used from PHP easily. Here is how


More Information

Configuration

You will need php with the SoapClient class available.

The innovaphone PBX wsdl file is required. See Reference8:SOAP API for information how to obtain this file. To access older WSDL versions, you will need to change the WSDL URL setting (in const ___wsdl) and adapt to the required number of version booleans in the call to Initialize() in the pbx wrapper class.

If you have access to the internet, you can try out the sample code given below right away. Of course you may also adapt the sample script configuration and try with your own innovaphone PBX.

Running the Sample Code

To demonstrate SOAP usage with PHP, a simple script is presented that will allow you to initiate a call using a web page.

The following class innoPBX is used to wrap the (somewhat clumsy) PHP SOAP access mechanism:

<?php

// innovaphone PBX SOAP API PHP wrapper class //

class innoPBX extends SOAPClient {

   protected $___key; 		// the session key
   protected $___session; 	// the session id
   protected $___options = array(

// default SOAPClient::__construct options used by the class "connection_timeout" => 10, "exceptions" => true,

   );
   const ___wsdl = 'http://www.innovaphone.com/wsdl/pbx900.wsdl';
   // class constructor
   public function __construct(

$server, // the PBX IP $httpu, // the HTTP user id (e.g. "admin") $httpp, // the HTTP password (e.g. "ip800") $user = null, // the PBX user CN to work with $options = null, // extra or overriding options for SOAPClient::__construct $wsdl = null // the wsdl file location

   ) {	

$wsdl = ($wsdl === null) ? self::___wsdl : $wsdl; $usedoptions = array( // forced options 'login' => $httpu, 'password' => $httpp, 'location' => "http://$server/PBX0/user.soap", ); if (is_array($options)) $usedoptions += $options; // merge in user options $usedoptions += $this->___options; // merged in class global options

// construct parent class parent::__construct($wsdl, $usedoptions);

// get the connection (using and activating v9 wsdl) $init = $this->Initialize($user, "PHP SOAP Wrapper", true, true, true, true, true); $this->___key = $init['key']; $this->___session = $init['return'];

   }
   public function key() { return $this->___key; }
   public function session() { return $this->___session; }

}

?>

Save this code into a file named innopbx.class.php on your web server. This class is of course not required to use PHP SOAP with the innovaphone PBX API. However, it comes handy and should be generic enough to be useful in most cases.

The SOAP client uses the following code:

<?php

// get the innoPBX wrapper class require_once('innopbx.class.php');

// dummy classes to map SOAP results to (really would love to use namespaces here...) // you can add methods and variables to these classes as needed class innoUserInfo { }; class innoCallInfo { }; class innoAnyInfo { }; class innoGroup { }; class innoNo { }; class innoInfo { };


// config, adapt to your need // this data below will work with innovaphones demo PBX. Just register 2 phones as user-3 and user-4 and hve fun! $server = "demo.innovaphone.com"; $user = "SOAP"; $httpu = "demo"; $httpp = "demo"; $caller = "PBX User Four"; $destination = "130";

print "

";

// create connector to PBX
// class mapping is optional
$inno = new innoPBX($server, $httpu, $httpp, $user,
	    array('classmap' => array("UserInfo" => "innoUserInfo", 
				"CallInfo" => "innoCallInfo",
				"AnyInfo" => "innoAnyInfo",
				"Group" => "innoGroup",
				"No" => "innoNo",
				"Info" => "innoInfo",
			    )));
if ($inno->key() == 0) die("failed to login to PBX");

// show all methods supported by this object
print "All the functions provided by class innoPBX:\n";
print_r($inno->__getFunctions());
print "\n\n";

// get version info
$v = $inno->Version();

// show both types of infos list
function showInfos(&$poll, $head, $cn = "", $user = "", $call = "") {
    print $head . "\n";
    if ($cn !== null) {
	print count($poll->user) . " UserInfos\n";
	foreach($poll->user as $ui) {
	    if (($cn === "") || ($cn == $ui->cn)) {
		print "     {$ui->cn} ({$ui->h323} #{$ui->e164}) state {$ui->state}\n";
	    }
	}
    }
    if ($call !== null) {
	print count($poll->call) . " CallInfos\n";
	foreach($poll->call as $ci) {
	    if ((($user === "") || ($user == $ci->user)) &&
		(($call === "") || ($call == $ci->call))) {
		    print "    {$ci->user}/{$ci->call} {$ci->No[1]->h323} #{$ci->No[1]->e164} (remote {$ci->No[0]->h323} #{$ci->No[0]->e164}) msg {$ci->msg}\n";
		}
	}
    }
}

// retrieve the full user list.  Foreach object in the PBX, one userinfo is posted, terminated by an empty one
// You cannot assume that you will receive this list within a certain number of Poll results, so please iterate
print "Retrieving User list for "; foreach ($v as $name => $value) print "\n  $name=$value "; print "...\n\n";
$seen = false;
$i = 1;
while (!$seen) {
    $p = $inno->Poll($inno->session());
    showInfos($p, "Poll() result #$i", "", null, null); $i++;
    if ($p->user[count($p->user)-1]->cn == "") {
	// we have seen all entries
	print " --- END OF LIST ---\n\n";
	$seen = true;
	break;
    }
}

// create a call on behalf of some user
// first we need a user handle
print "\nObtaining a user handle for $caller...";
$uhandle = $inno->UserInitialize($inno->session(), $caller);
print " $uhandle\n";
if ($uhandle == 0) {
    die("cant get user handle for $caller");
}

// then we create a call
print "Creating call from $caller to $destination...";
$call = $inno->UserCall($uhandle, null, $destination, null, 0, array());
print " $call\n";
if ($call == 0) {
    die("cant call on behalf of user $caller ($uhandle)");
}

// get call state(s) until call disappears
// note: you must at least poll for one call info related to this call, if you end
// the session right after UserCall, the call will not succeed!
$done = false;
while (!$done) {
    ob_flush();   // this is just to see the progress on the call states
    $p = $inno->Poll($inno->session());
    showInfos($p, "Call States #$i for #{$call}", $caller, $uhandle, $call); $i++;
    // see if there was a del event (there is ALWAYS a del event)
    // we could as well look for an event with active = false
    foreach ($p->call as $ci) {
	if (($ci->user == $uhandle) && 
	    ($ci->call == $call) &&
	    ($ci->msg == "del")) {
		print "\nCall terminated!\n";
		$done = true;
	    }
    }
}

// terminate the session
$e = $inno->End($inno->session());

?>

Save this into a file named innopbx.sample.php in the same directory of your web server.
To run the code, you need to examine and possibly adapt the configuration parameters in innopbx.sample.php:

// config, adapt to your need
// this data below will work with innovaphones demo PBX.  Just register 2 phones as user-3 and user-4 and hve fun!
$server = "demo.innovaphone.com";
$user = "SOAP";
$httpu = "demo";
$httpp = "demo";
$caller = "PBX User Four";
$destination = "130";


This configuration will work right away with our publicly available demo PBX.  You simply need to register 2 phones with the user-3 and user-4 users.

Of course you can also use your own PBX.  Set the configuration parameters as follow:
$server IP address of your innovaphone PBX
$user CN (aka Long name) of a PBX user that is active group member of a group where all others are (active or passive) members of
$httpu the admin account of the box running the innovaphone PBX (e.g.admin)
$httpp the admin password of this box (e.g. ipxxx)
$caller CN (aka Long name) of a PBX user you will have the script make a call for
$destination the number to be called
When the configuration parameters are set, you can point your browser to http://your-web-server-ip/path-to-folder/innopbx.sample.php which should create a call on $callers phone. Please note that you need internet access to retrieve the wsdl from innovaphone's web site.

How the code works

The innovaphone PBX API wrapper class

This class is derived from (extends in PHP speak) the standard SOAPClient class. It basically simplifies the use of the standard class and performs the required call to Initialize within its constructor. The constructor takes the following arguments: public function __construct($server, $httpu, $httpp, $user, $options = null, $wsdl = null);
$server, $httpu, $httpp, $user see table above
$options an optional array of further options to SOAPClient::__construct. Normally not required. See the PHP SOAPClient class documentation for details.
$wsdl the optional URI of the pbx wsdl file. Please note that you should use pbx10_00.wsdl instead of pbx.wsdl, as this is the more recent version of the wsdl. By default, the wsdl is received from the innovaphone web and (subject to PHP configuration options) cached in PHP's wsdl cache. If you intend to supply it locally (which is recommended, as you otherwise depend on www.innovaphone.com being available each time your program runs), use a file:// URI.
Calls to PBX API functions defined in the wsdl can be done directly through an instance of class innoPBX. These member functions - which are neither defined in class innoPBX nor in class SOAPClient - are created automagically by reading the wsdl: $v = $inno->Version(); To see the functions available and their PHP signatures, you may call $inno = new innoPBX(...); print_r($inno->$inno->__getFunctions()); Many PBX SOAP API functions required either the session-key or session-handle. These are available from the class instance for convenience: $p = $inno->Poll($inno->session());

How to use the innovaphone PBX API wrapper class with SSL

3rd party input
this is 3rd party content not provided by innovaphone, see history for authors.
In order to make a secure connection to the PBX, you have to change the inno.class.php as follows: 'location' => "https://$server/PBX0/user.soap" Note: in PHP 5.6 all encrypted client streams now enable peer verification by default. By default, this will use OpenSSL's default CA bundle to verify the peer certificate. See: OpenSSL changes in PHP 5.6.x To disable peer verification for the soap connection, you have to pass this as an option to the constructor: $context = stream_context_create(array( 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => false ) )); $options = array('stream_context' => $context); $inno = new innoPBX($server, $httpu, $httpp, $user, $options, $wsdl); More information on stream_context_create and ssl options: stream_context_create and SSL context options

How PHP maps SOAP parameters to method parameters and results

The mapping of parameters is pretty straight forward. Arguments passed in to a SOAP method are passed as a value parameters to the class methods. The thing to understand is that return values are always passed as return values, never as by-reference method arguments. If a SOAP method returns a single item, then it is returned by the function directly with appropriate type: int UserInitialize(int $session, string $user); The single return value from the UserInitialize SOAP method is returned as int by the UserInitialize innoPBX-method. If the SOAP methods returns multiple items, then the corresponding class method will return an array: array Initialize(string $user, string $appl); will return an array such as array( ['return'] => value ['key'] => value ) In the method signature printed out by __getFunctions() this looks like list(int $return, int $key) Initialize(string $user, string $appl)

The sample class user

This section will discuss the sample code. It is not a decent description of the PBX SOAP API. For this, see the related articles. A new innoPBX class instance object $inno is created using the values from the configuration variables discussed above. $inno = new innoPBX($server, $httpu, $httpp, $user, array('classmap' => array("UserInfo" => "innoUserInfo", "CallInfo" => "innoCallInfo", "AnyInfo" => "innoAnyInfo", "Group" => "innoGroup", "No" => "innoNo", "Info" => "innoInfo", ))); The option fifth argument will add a classmap entry to the options passed to SOAPClient::__construct. If this is done, the SOAP class will use your defined classes when returning values to the caller. Otherwise, structured return values will be indexed arrays (using the element names as array indexes). This is neat, but not required for the class to function. When Initialize (which is done implicitly in the innoPBX constructor) was successfull, one UserInfo class object per PBX object is posted to the caller. This list is terminated by an empty entry (more precisely, an entry with an empty cn member). The while (!$seen) { $p = $inno->Poll($inno->session()); ... loop will retrieve and show all these entries. To be able to perform calls, a user session must be opened by $uhandle = $inno->UserInitialize($inno->session(), $caller); The $uhandle retrieved will identify the user to be worked with on subsequent calls. A call on behalf of $caller is then initiated: $call = $inno->UserCall($uhandle, null, $destination, null, 0, array()); When UserCall returns a non-zero call handle, the call is initiated and can be monitored by examining CallInfo events returned by subsequent Poll() calls: while (!$done) { $p = $inno->Poll($inno->session()); this will retrieve events from the PBX if (($ci->user == $uhandle) && ($ci->call == $call) && ($ci->msg == "del")) { print "\nCall terminated!\n"; $done = true; until a del event is seen for the call previously created by UserCall. Please note that any number of call events may occur, e.g. because someone else called $caller. You cannot assume that all events retrieved are related to the call you created. Also, any number of UserInfo events may be retrieved. Please note that there is no need to consume all of the events related to the call for it to work. However, you must not terminate the session before the call is actually proceeding. If you do so, strange things will happen. To be sure the call proceeds, it is ok to wait for just any CallInfo event related to the call. You can then safely terminate your session and exit the web page.

Working with Call States from CallInfo

The state field of the CallInfo contains a bit field encoded information about direction of the call, hold information and an actual call state. Here is an example how to get relevant states: <?php // decimal state value from CallInfo // $callstate = 2; // call state? switch ($callstate & 0xF) { case 1: echo ("setup\r\n"); break; case 2: echo ("setup-ack\r\n"); break; case 3: echo ("call-proc\r\n"); break; case 4: echo ("Alert\r\n"); break; case 5: echo ("Connect\r\n"); break; case 6: echo ("disconnect sent\r\n"); break; case 7: echo ("disconnect received\r\n"); break; case 8: echo ("parked\r\n"); break; default: echo ("UNKNOWN STATE: " . ($callstate & 0xF) . "\r\n"); break; } // call direction? switch ($callstate & 0x80) { case 0: echo ("inbound call\r\n"); break; case 128: echo ("outbound call\r\n"); break; default: echo ("UNKNOWN STATE: " . ($callstate & 0x80) . "\r\n"); break; } // is call on hold? switch ($callstate & 0x100) { case 0: echo ("active call\r\n"); break; case 256: echo ("call on hold\r\n"); break; default: echo ("UNKNOWN STATE: " . ($callstate & 0x100) . "\r\n"); break; } // is call being held by peer? switch ($callstate & 0x200) { case 0: echo ("active call\r\n"); break; case 512: echo ("active call put on hold by peer\r\n"); break; default: echo ("UNKNOWN STATE: " . ($callstate & 0x200) . "\r\n"); break; } ?>

More Sample Code

Much more elaborate SOAP sample code is available for download from the samples section on http://download.innovaphone.com. Note that if you want to use innovaphone's demo PBX to test the code, you need to change the PBX IP address from 145.253.157.200 to demo.innovaphone.com in the downloaded code. This code shows how to deal with call control on master/slave scenarios as well as how to perform PBX configuration updates or PBX object creation using the SOAP Admin function. Currently, there are the following sample functions available: * create a SOAP session to the master PBX * create a user session on a device * initiate a call via SOAP and terminate it once connected * List all available SOAP functions * Show an object's configuration using the Admin() function * clone of adminshow which forces config=1 * Modify a user object using the Admin() function * Clone a PBX object using the Admin() function * Add call forwarding using Admin() function * Delete call forwarding using Admin() function * Get the PBX key * Generate an encrypted PBX user password * Set a new password for user * Get the password of a PBX object in clear * Decrypt a password from VARs (only works for boxes with default admin password!) * Encrypt a password for use in VARs (only works for boxes with default admin password!) * Find matching users Although this code is written in PHP5, it is also good reading if you do not intend to use PHP as it exemplifies the principles of using SOAP and the SOAP Admin() function.

Download

*Download the complete file package of scripts and files described in this article.

Related Articles

* Reference:SOAP API * Reference7:SOAP API * Reference8:SOAP API * Reference9:Concept SOAP API * Reference10:Concept SOAP API * Howto:Use the innovaphone Demo PBX * Howto:Using the SOAP Admin Function Search all SOAP sample code in the wiki