PHP Soap Client
PHP is a terrific language for processing the AXL Soap API. The built-in Soap handling is very easy to use. Plus, you can install PHP separately from your web server and run PHP scripts from the command line like you would any other scripting language. This tutorial uses PHP 5.6.4 and CUCM 10.5 along with the AXL toolkit that comes with CUCM 10.5.
Set Up the Soap Client
Set up the Soap client
<?php
$host="cucm-pub.abc.inc";
$username="Administrator";
$password="password";
$context =
stream_context_create(array('ssl'=>array('verify_peer_name'=>true,
'allow_self_signed'=>true,
'cafile'=>"/var/www/html/PHP-Sample/cucm-pub.abc.inc"
)));
$client = new SoapClient("/var/www/html/PHP-Sample/AXLAPI.wsdl",
array('trace'=>true,
'exceptions'=>true,
'location'=>"https://".$host.":8443/axl",
'login'=>$username,
'password'=>$password,
'stream_context'=>$context
));
?>
The first thing you want to do is instantiate a Soap client
. You need to specify the AXLAPI.wsdl
WSDL file as the first parameter. In this case, the WSDL file is in the same directory as the PHP code. You should also have the AXLSoap.xsd
and AXLEnums.xsd
files in the same directory. You can get these files from your CUCM installation via the web user interface by going to Application->Plugins
, click Find
and then download the Cisco AXL Toolkit.
Securing the Connection
Securing the connection
<?php
$context = stream_context_create(array('ssl'=>array('verify_peer_name'=>true,
'allow_self_signed'=>true,
'cafile'=>"/var/www/html/PHP-Sample/DS-UCM105.cisco.com"
)));
?>
The AXL service requires a secure HTTPS connection to work. It is best practice,certainly in production, to have the client authenticate the AXL service by checking its certificate. By default PHP will make this attempt, and will fail with a cannot connect to host
error if the certificate check fails.
The process for obtaining the CUCM web certificate and making it available to PHP for authentication can differ by browser, OS and PHP config. The following process was used with this sample:
- Use Firefox to browse to the CUCM host, for example 'https://ds-ucm105.cisco.com'
- In the address bar to the far left, click on the 'lock' icon
- Click on More Information > View Certificate > Details
- Click on Export and save the certificate to the PHP application's working directory in 'X.509 Certificate (PEM)' format
Note: The 'stream_context'=>$context
parameter given in the SoapClient constructor. This stream context allows specific parameters for handling of the request context to be given – here we will request that the SSL implementation use the request's host-name to verify the certificate match, that the AXL service's self-signed-certificate be allowed, and that the CUCM certificate previously downloaded above be used as the basis for the check.
Note: To disable certificate checking, for example during development, remove the verify_peer_name
and cafile
array elements, as shown in the right hand panel.
Disable certificate checking
<?php
$context = stream_context_create(array('ssl'=>array('allow_self_signed'=>true)));
?>
getPhone API in PHP
How to Execute a Soap Call
getPhone
<?php
$response = $client->getPhone(array("name"=>"SEP010101010101"));
?>
Now that you have instantiated a client
object, you're ready to implement any of the APIs specified in the WSDL. You call getPhone
with $client->getPhone
. In this first example, we simply specify the name of the phone (you have a choice between specifying the name
or the uuid
of the phone). That's all there is to it.
The XML for the getPhone Soap Call
getPhone XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/10.5">
<soapenv:Header/>
<soapenv:Body>
<ns:getPhone sequence="?">
<name>SEP010101010101</name>
<!-- OR <uuid>uuid-goes-here</uuid> -->
<returnedTags ctiid="?" uuid="?">
<name/>
<description/>
<product/>
<model/>
<class/>
<protocol/>
</returnedTags>
</ns:getPhone>
</soapenv:Body>
</soapenv:Envelope>
There are times when you only want to retrieve certain bits of information about a phone. You can specify what you want to see by defining returnedTags
, as shown in this XML sample. In this next example, we narrow the returned data down to name
, description
, product
, model
, class
, and protocol
, as shown in the XML.
Specifying name and returnedTags
Specifying name and returnedTags
<?php
$payload = array(
"name"=>"SEP010101010101",
"returnedTags"=>array("name"=>"",
"description"=>"",
"product"=>"",
"class"=>"",
"protocol"=>""
)
);
$response = $client->getPhone($payload);
?>
Note that we created a single array of two elements, name
and returnedTags
. However, the latter element, returnedTags
points to another array of the names of the elements we want returned. Each of these key=>value
pairs points to an empty string. This is equivalent to creating a closed XML tag like <name/>
or <description/>
.
Getting the Response
A trick to peek at the complete
$response
<?php
echo "<pre>";
var_dump(get_object_vars($response));
echo "</pre>";
?>
This time, let's take a look at the $response
, which is an array of objects you can traverse to get the returned information. If you're not sure how to interpret the $response
object that comes back, you can employ this little trick to examine the information.
This code will echo to your browser the entire structure of the $response
object.
Sample Excerpt of the $response array/object
Sample excerpt of the $response array/object
<?php
array(1) {
["return"]=>
object(stdClass)#3 (1) {
["phone"]=>
object(stdClass)#4 (7) {
["name"]=>
string(15) "SEP010101010101"
["description"]=>
string(13) "npetrele CIPC"
["product"]=>
string(21) "Cisco IP Communicator"
["class"]=>
string(5) "Phone"
["protocol"]=>
string(3) "SIP"
["ctiid"]=>
int(21)
["uuid"]=>
string(38) "{BCD3D84F-AE8C-7A97-D555-DCB326D0DEEB}"
}
}
}?>
This is a sample of the information as a result of the var_dump
. The main key in this array is return
, which points to the object phone
, which, in turn, points to various properties of that object, strings of data. So if you want to see the name of the phone, you would access the name with $response->return->phone->name
.
Accessing the Elements of the $response
Now you know how to access the details you want from $response
<?php
echo("Name: ".$response->return->phone->name)."<br>";
echo("Description: ".$response->return->phone->description)."<br>";
echo("Product: ".$response->return->phone->product)."<br>";
echo("Class: ".$response->return->phone->class)."<br>";
echo("Protocol: ".$response->return->phone->protocol)."<br>";
?>
Now that we know the structure of the $response
, we can access the data we need with a handful of simple lines of code.
This completes our getPhone
example.
listUser -- A More Complex AXL Request
Specify searchCriteria and returnedTags
XML for listUser defining returned tags
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/10.5">
<soapenv:Header/>
<soapenv:Body>
<ns:listUser sequence="?">
<searchCriteria>
<userid>%</userid>
</searchCriteria>
<returnedTags uuid="?">
<firstName/>
<lastName/>
<userid/>
</returnedTags>
</ns:listUser>
</soapenv:Body>
</soapenv:Envelope>
Now let's look at an AXL request that includes both searchCriteria
and returnedTags
.
Examine the XML for this request. If you check the WSDL file, you'll see that you can search by firstName
, lastName
, userid
, and department
. This example searches only by userid
, and we use the wild card %
so that we'll end up listing every user.
This example also specifies firstName
, lastName
and userid
as the returned tags.
A Complete Example of a listUser Request
Here's how you translate that XML into PHP Soap code, and then list the results
<?php
$host="cucm-pub.abc.inc";
$username="Administrator";
$password="password";
$context = stream_context_create(array('ssl'=>array('verify_peer_name'=>true,
'allow_self_signed'=>true,
'cafile'=>"/var/www/html/PHP-Sample/cucm-pub.abc.inc"
)));
$client = new SoapClient("/var/www/html/PHP-Sample/AXLAPI.wsdl",
array('trace'=>true,
'exceptions'=>true,
'location'=>"https://".$host.":8443/axl",
'login'=>$username,
'password'=>$password,
'stream_context'=>$context
));
// Just set every tag you want returned to an empty string ("") in this array
$returnedTags = array("firstName"=>"","lastName"=>"","userid"=>"");
// "%" is a wild card to find every user
$searchCriteria = array("userid"=>"%");
try {
$response = $client->listUser(array("returnedTags"=>
$returnedTags,"searchCriteria"=>$searchCriteria));
}
catch (SoapFault $sf) {
echo "SoapFault: " . $sf . "<BR>";
}
catch (Exception $e) {
echo "Exception: ". $e ."<br>";
}
// Iterate through array of returned values (as specified by $returnedTags)
foreach($response->return->user as $user) {
echo("First Name: ".$user->firstName."<br>");
echo("Last Name: ".$user->lastName."<br>");
echo("User ID: ".$user->userid."<br>");
echo("<hr>");
}
?>
Here is a working example of listUser
, including code to iterate through the returned values and echo them to the screen or browser. We pass both the search criteria and specified returned tags as arrays to the Soap client. As we did in the getPhone
example, we specify key=>value
pairs pointing to empty strings for the returned tags.
addUser - How to Handle Duplicate Tags
The associatedGroups Tag has Multiple userGroup Tags
The associatedGroups tag has multiple userGroup tags
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/10.5">
<soapenv:Header/>
<soapenv:Body>
<ns:addUser sequence="?">
<user>
<firstName>Joey</firstName>
<lastName>Bishop</lastName>
<userid>joey</userid>
<password>bishop</password>
<enableCti>true</enableCti>
<enableMobility>true</enableMobility>
<imAndPresenceEnable>true</imAndPresenceEnable>
<associatedGroups>
<userGroup>
<name>Application Client Users</name>
</userGroup>
<userGroup>
<name>Standard CTI Enabled</name>
</userGroup>
<userGroup>
<name>Standard CTI Secure Connection</name>
</userGroup>
<userGroup>
<name>Third Party Application Users</name>
</userGroup>
</associatedGroups>
</user>
</ns:addUser>
</soapenv:Body>
</soapenv:Envelope>
Up until now, we've been passing arrays to the AXL functions. That is precisely what makes AXL and PHP so easy.
However, arrays can present a problem when the XML must include duplicate tags. For example, suppose you want to add a user and define a number of the user's associated groups. Note that this would require duplicate userGroup
keys.
This Will Not Work
This will not work
<?php
array(
"userGroup"=>array("name"=>"Application Client Users"),
"userGroup"=>array("name"=>"Standard CTI Enabled"),
"userGroup"=>array("name"=>"Standard CTI Secure Connection"),
"userGroup"=>array("name"=>"Third Party Application Users")
);
?>
You can't load a PHP array with multiple key=>value
pairs where the key is always userGroup
. Actually, PHP won't complain if you define an array that way, but you won't get the correct results, because PHP expects array keys to be unique.
Create a userGroup Class
Instead, create a userGroup class
<?php
class userGroup
{
public $name;
}
?>
Because you can't use an array of userGroup
tags, use instead an array of objects with properties. First, create the class userGroup
with the property name
.
Create Objects Based on the userGroup Class
Create objects instead of an array of
key=>value
pairs
<?php
$userGroup1 = new userGroup();
$userGroup2 = new userGroup();
$userGroup3 = new userGroup();
$userGroup4 = new userGroup();
$userGroup1->name = 'Application Client Users';
$userGroup2->name = 'Standard CTI Enabled';
$userGroup3->name = 'Standard CTI Secure Connection';
$userGroup4->name = 'Third Party Application Users';
?>
Now you can create multiple userGroup
objects and define the name property as you would have if it was an array value.
Load the Objects into an Array
Array of objects
<?php
$something = array(
$userGroup1,
$userGroup2,
$userGroup3,
$userGroup4);
?>
Then you can load these userGroup
objects into an array. An array of objects does not violate the unique key requirement for PHP arrays of keys in key=>value
pairs.
Complete addUser Code Sample
Complete code sample integrating the array of objects
<?php
$host="cucm-pub.abc.inc";
$username="Administrator";
$password="password";
$context = stream_context_create(array('ssl'=>array('verify_peer_name'=>true,
'allow_self_signed'=>true,
'cafile'=>"/var/www/html/PHP-Sample/cucm-pub.abc.inc"
)));
$client = new SoapClient("/var/www/html/PHP-Sample/AXLAPI.wsdl",
array('trace'=>true,
'exceptions'=>true,
'location'=>"https://".$host.":8443/axl",
'login'=>$username,
'password'=>$password,
'stream_context'=>$context
));
class userGroup
{
public $name;
}
echo "<p>Add User Test</p>";
$userGroup1 = new userGroup();
$userGroup2 = new userGroup();
$userGroup3 = new userGroup();
$userGroup4 = new userGroup();
$userGroup1->name = 'Application Client Users';
$userGroup2->name = 'Standard CTI Enabled';
$userGroup3->name = 'Standard CTI Secure Connection';
$userGroup4->name = 'Third Party Application Users';
$user=array("user"=>
array("firstName"=>"Joey",
"lastName"=>"Bishop",
"userid"=>"joey",
"password"=>"bishop",
"enableCti"=>"true",
"enableMobility"=>"true",
"imAndPresenceEnable"=>"true",
"presenceGroupName"=>"Standard Presence group",
"associatedGroups"=>array(
$userGroup1,
$userGroup2,
$userGroup3,
$userGroup4)
)
);
try {
$response = $client->addUser($user);
}
catch (SoapFault $sf) {
echo "SoapFault: " . $sf . "<BR>";
}
catch (Exception $e) {
echo "Exception: ". $e ."<br>";
}
?>
Now let's put that all together as a sample application that adds the user Joey Bishop.