Howto:SOAP API PHP5 Sample Code: Difference between revisions

From innovaphone wiki
Jump to navigation Jump to search
(New page: ==Applies To== This information applies to * any innovaphone PBX platform * web server running PHP 5 innovaphone PBX web services can be used from PHP easily. Here is how <!-- web serv...)
(No difference)

Revision as of 20:48, 24 January 2008

Applies To

This information applies to

  • any 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 Reference:SOAP API for information how to obtain this file.

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 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/pbx.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,		// 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
	$init = $this->Initialize($user, "PHP SOAP Wrapper");
	$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 = "145.253.157.200";
$user = "SOAP";
$httpu = "demo";
$httpp = "demo";
$caller = "PBX User Four";
$destination = "130";

print "<pre>";

// 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} (remote {$ci->h323} #{$ci->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 = !initial;
$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 kust 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 = "145.253.157.200";
$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 pbx501.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, 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 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 namess array indexes). This is neat, but not required for class to function.

When Initialize (which is done implicitly in the innoPBX constructor) was successfull, one UserInfo class object is posted per PBX object 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 related to the call you created. Also, any number of UserInfo events will 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 proceed, 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.


Related Articles

Reference:SOAP API